diff --git a/frontend/e2e/dashboard-screenshots.spec.ts b/frontend/e2e/dashboard-screenshots.spec.ts index 2566b056..82498796 100644 --- a/frontend/e2e/dashboard-screenshots.spec.ts +++ b/frontend/e2e/dashboard-screenshots.spec.ts @@ -1,45 +1,3 @@ -/** - * Captures dashboard screenshots at multiple viewport sizes and in both - * light and dark theme. Output goes to proofshot-artifacts/dashboard/. - * Run via: npx playwright test e2e/dashboard-screenshots.spec.ts - */ -import { test } from '@playwright/test'; -import path from 'path'; -import fs from 'fs'; -import { fileURLToPath } from 'url'; +import { captureProofshots } from './proofshots'; -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const outDir = path.join(__dirname, '../../proofshot-artifacts/dashboard'); -fs.mkdirSync(outDir, { recursive: true }); - -const viewports = [ - { name: 'mobile', width: 390, height: 844 }, - { name: 'tablet', width: 768, height: 1024 }, - { name: 'desktop', width: 1440, height: 900 } -]; - -for (const vp of viewports) { - for (const theme of ['light', 'dark'] as const) { - test(`dashboard – ${vp.name} – ${theme}`, async ({ page }) => { - await page.setViewportSize({ width: vp.width, height: vp.height }); - await page.goto('/'); - - // Apply theme - await page.evaluate((t) => { - document.documentElement.setAttribute('data-theme', t); - localStorage.setItem('theme', t); - }, theme); - - // Wait for the main content to be rendered. - // 'networkidle' is unreliable in SvelteKit dev mode due to the HMR WebSocket. - await page.waitForLoadState('domcontentloaded'); - // Wait for at least one dashboard widget or the search bar to be visible - await page.waitForSelector('main', { state: 'visible' }); - - await page.screenshot({ - path: path.join(outDir, `dashboard-${vp.name}-${theme}.png`), - fullPage: true - }); - }); - } -} +captureProofshots('/', 'dashboard'); diff --git a/frontend/e2e/proofshots.ts b/frontend/e2e/proofshots.ts new file mode 100644 index 00000000..44124fee --- /dev/null +++ b/frontend/e2e/proofshots.ts @@ -0,0 +1,58 @@ +/** + * Shared proofshot helper for Playwright. + * + * Usage in any spec file: + * import { captureProofshots } from './proofshots'; + * captureProofshots('/persons', 'persons'); + * + * This registers one test per viewport × theme combination. + * Screenshots are saved to proofshot-artifacts/{featureName}/. + */ +import { test } from '@playwright/test'; +import path from 'path'; +import fs from 'fs'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +const viewports = [ + { name: 'mobile', width: 390, height: 844 }, + { name: 'tablet', width: 768, height: 1024 }, + { name: 'desktop', width: 1440, height: 900 } +]; + +/** + * Registers Playwright tests that navigate to `url`, apply each theme, + * and capture full-page screenshots at all standard viewports. + * + * @param url The path to screenshot (e.g. '/', '/persons', '/admin') + * @param featureName Used as the output directory name and screenshot file prefix + */ +export function captureProofshots(url: string, featureName: string): void { + const outDir = path.join(__dirname, '../../proofshot-artifacts', featureName); + fs.mkdirSync(outDir, { recursive: true }); + + for (const vp of viewports) { + for (const theme of ['light', 'dark'] as const) { + test(`${featureName} – ${vp.name} – ${theme}`, async ({ page }) => { + await page.setViewportSize({ width: vp.width, height: vp.height }); + await page.goto(url); + + // Apply theme via data-theme attribute and localStorage + await page.evaluate((t) => { + document.documentElement.setAttribute('data-theme', t); + localStorage.setItem('theme', t); + }, theme); + + // 'networkidle' is unreliable in SvelteKit dev mode due to the HMR WebSocket. + await page.waitForLoadState('domcontentloaded'); + await page.waitForSelector('main', { state: 'visible' }); + + await page.screenshot({ + path: path.join(outDir, `${featureName}-${vp.name}-${theme}.png`), + fullPage: true + }); + }); + } + } +}