// Automated accessibility scan (docs/QA_PLAN.md B14). Runs axe-core on each page // and fails on critical/serious WCAG violations. Public pages are covered here; // add authenticated pages once a login fixture exists (see e2e/README.md). This // is the automated companion to the manual keyboard/SR a11y checks — it re-runs // every cycle so contrast/role regressions can't sneak back in. const { test, expect } = require('@playwright/test'); const AxeBuilder = require('@axe-core/playwright').default; const PUBLIC_PAGES = ['/login', '/about', '/privacy']; for (const path of PUBLIC_PAGES) { test(`no critical/serious a11y violations on ${path}`, async ({ page }) => { await page.goto(path); await page.waitForLoadState('networkidle'); const results = await new AxeBuilder({ page }) .withTags(['wcag2a', 'wcag2aa']) .analyze(); const blocking = results.violations.filter( (v) => v.impact === 'critical' || v.impact === 'serious', ); const summary = blocking .map((v) => `- [${v.impact}] ${v.id}: ${v.help} (${v.nodes.length} node(s))`) .join('\n'); expect(blocking, `axe violations on ${path}:\n${summary}`).toEqual([]); }); }