Files
2026-05-27 23:29:53 +01:00

44 lines
2.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Architecture
Two cooperating helpers share one threshold, one viewport, and one font/animation discipline so the e2e and Storybook baselines stay comparable.
### Adapter choice
- **e2e path:** Playwright's built-in `expect(page).toHaveScreenshot()` — already in the dependency closure, supports per-OS baselines natively, threshold semantics (`maxDiffPixelRatio`, `maxDiffPixels`) are well documented. No `pixelmatch` direct dep needed.
- **Storybook path:** `@storybook/test-runner` is the canonical Storybook→Playwright bridge. It exposes `preVisit` / `postVisit` hooks where we capture screenshots using the same Playwright `Page` instance, so the comparator and threshold match the e2e path bit-for-bit.
A pure-Node `pixelmatch` helper was rejected: it would fork the comparator, drift in floating-point handling between OSes, and double the surface to maintain.
### Default thresholds
- `maxDiffPixelRatio: 0.005` (0.5%). Tighter ratios (e.g. 0.001) produce noise from sub-pixel font rendering on different GPU drivers.
- `animations: 'disabled'`, `caret: 'hide'`, `scale: 'css'`.
- Viewport: 1280×720 default. Stories pin to the same default unless the story sets an explicit `parameters.viewport`.
- `prefers-reduced-motion: reduce` forced via `page.emulateMedia`.
### OS matrix
Baselines are stored per platform: `__snapshots__/<linux|darwin|win32>/...`. CI MUST run at least the platforms it intends to gate on. A platform with no baseline directory MUST skip the comparison (no implicit pass) and emit a warning.
### Baseline-update workflow
1. Developer runs `bunx turbo test --filter=<pkg> -- --update-snapshots` locally.
2. Diff is committed in a **separate, review-tagged commit** prefixed `chore(visual): refresh baselines — <reason>`. Squashing into feature commits is forbidden.
3. PR reviewer compares before/after PNGs in the diff view; CI re-runs the comparator on the new baselines to catch accidental cross-platform drift.
### Determinism levers
- Fonts: `await document.fonts.ready` after `networkidle`. Web fonts that load lazily are the #1 source of flake.
- Color scheme: stories with `parameters.colorScheme === 'dark'` toggle via `page.emulateMedia({ colorScheme: 'dark' })` before capture.
- Time: any time-display surfaces under test must already accept an injected `Clock` per `openspec/project.md`; visual specs SHALL pass a `FakeClock` set to a fixed instant.
### Error model
`VisualRegressionError extends TestingE2eError` for the e2e path, `StorybookVisualError extends TestingDomError` for the Storybook path. Each carries `{ code, cause?, context: { baselinePath, actualPath, diffPath, pixelRatio } }`.
### Cross-links
- Release-readiness gate: `../enterprise-testbed-verification/proposal.md`.
- Audit driver: `/mnt/s/web/genesis/docs/superpowers/specs/2026-04-25-test-suite-audit.md` §2 row 2.
- Project rules: `/mnt/s/web/genesis/CLAUDE.md` "Web App & Page Verification".