veza/tests/e2e/audit/accessibility/01-axe-wcag.spec.ts
senke 463ad5386b test: update e2e test suite and add audit tests
Refine auth, player, tracks, playlists, search, workflows, edge cases,
forms, responsive, network errors, error boundary, performance, visual
regression, cross-browser, profile, smoke, storybook, chat, and session
tests. Add audit test suite (accessibility, ethical, functional, design
tokens). Update test helpers and visual snapshots.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 16:06:26 +01:00

100 lines
4 KiB
TypeScript

import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
import { loginViaAPI, navigateTo } from '../helpers';
import { TEST_USERS, ROUTES } from '../design-tokens';
test.describe('ACCESSIBILITÉ — axe-core WCAG AA sur chaque page', () => {
// --- Pages publiques ---
for (const route of ROUTES.public) {
test(`[PUBLIC] ${route.name} (${route.path}) — zéro violation WCAG AA critique`, async ({ page }) => {
await navigateTo(page, route.path);
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
.exclude('[aria-hidden="true"]') // Ignorer les éléments cachés
.analyze();
const critical = results.violations.filter(v => v.impact === 'critical' || v.impact === 'serious');
for (const violation of results.violations) {
console.log(`[AXE] [${violation.impact?.toUpperCase()}] ${violation.id}: ${violation.description}`);
console.log(` Help: ${violation.helpUrl}`);
for (const node of violation.nodes.slice(0, 3)) {
console.log(` Element: ${node.html.slice(0, 100)}`);
console.log(` FIX: ${node.failureSummary}`);
}
}
expect(critical.length,
`${critical.length} violation(s) WCAG critique(s) sur ${route.path}:\n` +
critical.map(v =>
`• [${v.impact}] ${v.id}: ${v.description}\n` +
` URL: ${v.helpUrl}\n` +
v.nodes.slice(0, 3).map(n =>
` Element: ${n.html.slice(0, 80)}\n FIX: ${n.failureSummary}`
).join('\n')
).join('\n\n')
).toBe(0);
});
}
// --- Pages protégées ---
for (const route of ROUTES.listener.slice(0, 12)) {
test(`[PROTECTED] ${route.name} (${route.path}) — zéro violation WCAG AA critique`, async ({ page }) => {
await loginViaAPI(page, TEST_USERS.listener.email, TEST_USERS.listener.password);
await navigateTo(page, route.path);
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
.exclude('[aria-hidden="true"]')
.analyze();
const critical = results.violations.filter(v => v.impact === 'critical' || v.impact === 'serious');
for (const violation of results.violations) {
console.log(`[AXE] [${violation.impact?.toUpperCase()}] ${violation.id}: ${violation.description}`);
for (const node of violation.nodes.slice(0, 3)) {
console.log(` Element: ${node.html.slice(0, 100)}`);
console.log(` FIX: ${node.failureSummary}`);
}
}
expect(critical.length,
`${critical.length} violation(s) WCAG critique(s) sur ${route.path}:\n` +
critical.map(v =>
`• [${v.impact}] ${v.id}: ${v.description}\n` +
v.nodes.slice(0, 3).map(n =>
` FIX: ${n.failureSummary}`
).join('\n')
).join('\n\n')
).toBe(0);
});
}
// --- Pages admin ---
for (const route of ROUTES.admin) {
test(`[ADMIN] ${route.name} (${route.path}) — zéro violation WCAG AA critique`, async ({ page }) => {
await loginViaAPI(page, TEST_USERS.admin.email, TEST_USERS.admin.password);
await navigateTo(page, route.path);
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
.exclude('[aria-hidden="true"]')
.analyze();
const critical = results.violations.filter(v => v.impact === 'critical' || v.impact === 'serious');
for (const violation of results.violations) {
console.log(`[AXE] [${violation.impact?.toUpperCase()}] ${violation.id}: ${violation.description}`);
for (const node of violation.nodes.slice(0, 2)) {
console.log(` FIX: ${node.failureSummary}`);
}
}
expect(critical.length,
`${critical.length} violation(s) WCAG critique(s) sur ${route.path}:\n` +
critical.map(v => `• [${v.impact}] ${v.id}: ${v.description}`).join('\n')
).toBe(0);
});
}
});