BillTracker/e2e/a11y.authed.spec.js

42 lines
1.4 KiB
JavaScript

// 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',
'/data',
];
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([]);
});
}