Add 2 E2E tests for dark mode system preference detection
All checks were successful
Deploy / deploy (push) Successful in 2m36s
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>
This commit is contained in:
@@ -4,7 +4,7 @@ This file is maintained by Ralph. Run `./ralph-sandbox.sh plan 3` to generate ta
|
||||
|
||||
## Current Status: Feature Complete
|
||||
|
||||
**Test Coverage:** 1014 unit tests (51 files) + 202 E2E tests (13 files) = 1216 total tests
|
||||
**Test Coverage:** 1014 unit tests (51 files) + 204 E2E tests (14 files) = 1218 total tests
|
||||
|
||||
All P0-P5 items are complete. The project is feature complete.
|
||||
|
||||
@@ -97,7 +97,7 @@ All P0-P5 items are complete. The project is feature complete.
|
||||
| PeriodDateModal | 22 | Period input modal |
|
||||
| Skeletons | 29 | Loading states with shimmer |
|
||||
|
||||
### E2E Tests (13 files, 202 tests)
|
||||
### E2E Tests (14 files, 204 tests)
|
||||
| File | Tests | Coverage |
|
||||
|------|-------|----------|
|
||||
| smoke.spec.ts | 3 | Basic app functionality |
|
||||
@@ -113,6 +113,7 @@ All P0-P5 items are complete. The project is feature complete.
|
||||
| plan.spec.ts | 7 | Plan page |
|
||||
| health.spec.ts | 3 | Health/observability |
|
||||
| mobile.spec.ts | 7 | Mobile viewport behavior, responsive layout, calendar mobile |
|
||||
| dark-mode.spec.ts | 2 | System preference detection, light/dark theme application |
|
||||
|
||||
---
|
||||
|
||||
@@ -124,11 +125,11 @@ These are optional enhancements to improve E2E coverage. Not required for featur
|
||||
| File | Tests | Description |
|
||||
|------|-------|-------------|
|
||||
| notifications.spec.ts | 3 | Notification preferences |
|
||||
| dark-mode.spec.ts | 2 | System preference detection |
|
||||
|
||||
### Completed Enhancements
|
||||
| File | Tests Added | Focus Area |
|
||||
|------|-------------|------------|
|
||||
| dark-mode.spec.ts | +2 | System preference detection (light/dark mode) |
|
||||
| garmin.spec.ts | +4 | Network error recovery (save, disconnect, status fetch, retry) |
|
||||
| calendar.spec.ts | +4 | Accessibility (ARIA, keyboard nav) |
|
||||
| settings.spec.ts | +1 | Error recovery on failed save |
|
||||
@@ -149,6 +150,7 @@ These are optional enhancements to improve E2E coverage. Not required for featur
|
||||
|
||||
## Revision History
|
||||
|
||||
- 2026-01-13: Added dark-mode.spec.ts with 2 E2E tests (system preference detection for light/dark mode)
|
||||
- 2026-01-13: Added 4 Garmin E2E tests (network error recovery for save, disconnect, status fetch, retry)
|
||||
- 2026-01-13: Added 8 E2E tests (calendar accessibility, settings error recovery, calendar mobile behavior)
|
||||
- 2026-01-13: Added mobile.spec.ts with 4 E2E tests (mobile viewport behavior, responsive layout)
|
||||
|
||||
90
e2e/dark-mode.spec.ts
Normal file
90
e2e/dark-mode.spec.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
// 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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user