BillTracker/e2e/a11y.authed.spec.js

28 lines
1.3 KiB
JavaScript
Raw Normal View History

// Automated accessibility scan of the AUTHENTICATED app (QA_PLAN B14). Companion
// to a11y.spec.js (public pages). Runs axe-core on the main in-app pages using the
// logged-in state from auth.setup, and fails on critical/serious WCAG violations
// so contrast/label/role regressions are caught every cycle.
const { test, expect } = require('@playwright/test');
const AxeBuilder = require('@axe-core/playwright').default;
const { STORAGE_STATE } = require('./constants');
test.use({ storageState: STORAGE_STATE });
const PAGES = ['/', '/bills', '/summary', '/spending', '/analytics', '/categories', '/snowball'];
for (const path of 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})\n ${v.nodes.map((n) => (n.html || '').slice(0, 140)).join('\n ')}`)
.join('\n');
if (blocking.length) console.log(`[a11y] ${path}\n${summary}\n`);
expect.soft(blocking, `axe critical/serious on ${path}:\n${summary}`).toEqual([]);
});
}