test(visual): regression baselines for stable list/landing pages
New `visual` project covers six low-volatility screens — portal login, dashboard, and the four core lists (clients/yachts/berths/invoices) — with full-page screenshots that diff to a 2% pixel-ratio tolerance. Animations and the cursor caret are disabled inline so transient rendering doesn't trigger flaky diffs. Detail screens (yacht detail, EOI dialog, invoice form steps) are intentionally deferred until we have stable per-id fixtures so snapshots don't drift with seed data. Regenerate with: pnpm exec playwright test --project=visual --update-snapshots Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -63,6 +63,18 @@ export default defineConfig({
|
||||
viewport: { width: 1440, height: 900 },
|
||||
},
|
||||
},
|
||||
{
|
||||
// Visual regression baselines. Regenerate with --update-snapshots after
|
||||
// intentional UI changes; otherwise pnpm exec playwright test --project=visual
|
||||
// diffs against the committed PNGs.
|
||||
name: 'visual',
|
||||
testMatch: /visual\/.*\.spec\.ts/,
|
||||
dependencies: ['setup'],
|
||||
use: {
|
||||
...devices['Desktop Chrome'],
|
||||
viewport: { width: 1440, height: 900 },
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
// Don't start the dev server — we expect it to already be running
|
||||
|
||||
67
tests/e2e/visual/snapshots.spec.ts
Normal file
67
tests/e2e/visual/snapshots.spec.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { test, expect, type Page } from '@playwright/test';
|
||||
|
||||
import { login, navigateTo } from '../smoke/helpers';
|
||||
|
||||
/**
|
||||
* Visual regression baselines for stable list/landing pages.
|
||||
*
|
||||
* On first run (or after intentional UI changes), regenerate:
|
||||
* pnpm exec playwright test --project=visual --update-snapshots
|
||||
*
|
||||
* Subsequent runs diff against the committed PNGs under
|
||||
* tests/e2e/visual/snapshots.spec.ts-snapshots/.
|
||||
*
|
||||
* Pages chosen are list/landing screens that don't depend on per-row
|
||||
* fixture data — they tolerate seed drift between runs. Detail screens
|
||||
* (yacht detail, EOI dialog, invoice form review) are intentionally
|
||||
* deferred until we have stable fixtures wired up.
|
||||
*/
|
||||
|
||||
const PAGES = [
|
||||
{ name: 'portal-login', path: '/portal/login', requireAuth: false },
|
||||
{ name: 'dashboard', path: '/dashboard', requireAuth: true },
|
||||
{ name: 'clients-list', path: '/clients', requireAuth: true },
|
||||
{ name: 'yachts-list', path: '/yachts', requireAuth: true },
|
||||
{ name: 'berths-list', path: '/berths', requireAuth: true },
|
||||
{ name: 'invoices-list', path: '/invoices', requireAuth: true },
|
||||
] as const;
|
||||
|
||||
async function settle(page: Page) {
|
||||
// Quiet the page so dynamic content (timers, spinners, blinking cursors)
|
||||
// doesn't cause flaky pixel diffs.
|
||||
await page.addStyleTag({
|
||||
content: `
|
||||
*, *::before, *::after {
|
||||
animation-duration: 0s !important;
|
||||
animation-delay: 0s !important;
|
||||
transition-duration: 0s !important;
|
||||
transition-delay: 0s !important;
|
||||
caret-color: transparent !important;
|
||||
}
|
||||
`,
|
||||
});
|
||||
await page.waitForLoadState('networkidle');
|
||||
// Tiny pause to let TanStack Query flush
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
|
||||
test.describe('Visual regression', () => {
|
||||
for (const p of PAGES) {
|
||||
test(`${p.name} matches baseline`, async ({ page }) => {
|
||||
if (p.requireAuth) {
|
||||
await login(page, 'super_admin');
|
||||
await navigateTo(page, p.path);
|
||||
} else {
|
||||
await page.goto(p.path);
|
||||
}
|
||||
|
||||
await settle(page);
|
||||
|
||||
await expect(page).toHaveScreenshot(`${p.name}.png`, {
|
||||
fullPage: true,
|
||||
// Tolerate small text-rendering differences across machines/runs.
|
||||
maxDiffPixelRatio: 0.02,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 150 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 153 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 204 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
Reference in New Issue
Block a user