All checks were successful
Deploy / deploy (push) Successful in 2m36s
Verifies that the app correctly applies light/dark mode styling based on the user's system preference (prefers-color-scheme). Tests cover both light and dark modes using Playwright's emulateMedia API. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
91 lines
2.9 KiB
TypeScript
91 lines
2.9 KiB
TypeScript
// ABOUTME: E2E tests for dark mode system preference detection.
|
|
// ABOUTME: Verifies app respects OS-level dark mode setting via prefers-color-scheme.
|
|
import { expect, test } from "@playwright/test";
|
|
|
|
// Helper to parse background color and determine if it's light or dark
|
|
function isLightBackground(colorValue: string): boolean {
|
|
// Try rgb/rgba format: rgb(255, 255, 255) or rgba(255, 255, 255, 1)
|
|
const rgbMatch = colorValue.match(
|
|
/rgba?\s*\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/,
|
|
);
|
|
|
|
if (rgbMatch) {
|
|
const r = parseFloat(rgbMatch[1]);
|
|
const g = parseFloat(rgbMatch[2]);
|
|
const b = parseFloat(rgbMatch[3]);
|
|
// Calculate relative luminance (simplified)
|
|
const luminance = (r + g + b) / 3;
|
|
return luminance > 128;
|
|
}
|
|
|
|
// Try oklch format: oklch(1 0 0) where first value is lightness
|
|
const oklchMatch = colorValue.match(/oklch\s*\(\s*([\d.]+)/);
|
|
if (oklchMatch) {
|
|
const lightness = parseFloat(oklchMatch[1]);
|
|
return lightness > 0.5;
|
|
}
|
|
|
|
// Try color() format with oklch: color(oklch 1 0 0)
|
|
const colorOklchMatch = colorValue.match(/color\s*\(\s*oklch\s+([\d.]+)/);
|
|
if (colorOklchMatch) {
|
|
const lightness = parseFloat(colorOklchMatch[1]);
|
|
return lightness > 0.5;
|
|
}
|
|
|
|
// Try lab() format: lab(100 0 0) where first value is lightness 0-100
|
|
const labMatch = colorValue.match(/lab\s*\(\s*([\d.]+)/);
|
|
if (labMatch) {
|
|
const lightness = parseFloat(labMatch[1]);
|
|
return lightness > 50;
|
|
}
|
|
|
|
// Default: couldn't parse, assume we need to fail the test
|
|
return false;
|
|
}
|
|
|
|
test.describe("dark mode", () => {
|
|
test("applies light mode styling when system prefers light", async ({
|
|
page,
|
|
}) => {
|
|
// Set system preference to light mode
|
|
await page.emulateMedia({ colorScheme: "light" });
|
|
|
|
await page.goto("/login");
|
|
await page.waitForLoadState("domcontentloaded");
|
|
|
|
// Get computed background color of the body
|
|
const bodyBgColor = await page.evaluate(() => {
|
|
return window.getComputedStyle(document.body).backgroundColor;
|
|
});
|
|
|
|
// In light mode, background should be white/light (oklch(1 0 0) = white)
|
|
const isLight = isLightBackground(bodyBgColor);
|
|
expect(
|
|
isLight,
|
|
`Expected light background in light mode, got: ${bodyBgColor}`,
|
|
).toBe(true);
|
|
});
|
|
|
|
test("applies dark mode styling when system prefers dark", async ({
|
|
page,
|
|
}) => {
|
|
// Set system preference to dark mode
|
|
await page.emulateMedia({ colorScheme: "dark" });
|
|
|
|
await page.goto("/login");
|
|
await page.waitForLoadState("domcontentloaded");
|
|
|
|
// Get computed background color of the body
|
|
const bodyBgColor = await page.evaluate(() => {
|
|
return window.getComputedStyle(document.body).backgroundColor;
|
|
});
|
|
|
|
// In dark mode, background should be dark (oklch(0.145 0 0) = near black)
|
|
const isLight = isLightBackground(bodyBgColor);
|
|
expect(
|
|
isLight,
|
|
`Expected dark background in dark mode, got: ${bodyBgColor}`,
|
|
).toBe(false);
|
|
});
|
|
});
|