30 lines
1.2 KiB
JavaScript
30 lines
1.2 KiB
JavaScript
|
|
// 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([]);
|
||
|
|
});
|
||
|
|
}
|