- Fix 98 TypeScript errors across 37 files: - Service layer double-unwrapping (subscriptionService, distributionService, gearService) - Self-referencing variables in SearchPageResults - FeedView/ExploreView .posts→.items alignment - useQueueSync Zustand subscribe API - AdminAuditLogsView missing interface fields - Toast proxy type, interceptor type narrowing - 22 unused imports/variables removed - 5 storybook mock data fixes - Align frontend API calls with backend endpoints: - Analytics: useAnalyticsView now calls /creator/analytics/dashboard (was /analytics) - Chat: chatService uses /conversations (was mock data), WS URL from backend token - Dashboard StatsSection: uses real /dashboard API data (was hardcoded zeros) - Settings: suppress 2FA toast error when endpoint unavailable - Fix marketplace products: seed uses 'active' status (was 'published') - Enrich seed: admin follows all creators (feed has content) - Optimize bundle: vendor catch-all 793KB→318KB gzip (-60%) Split into vendor-charts, vendor-emoji, vendor-swagger, vendor-media, etc. - Clean repo: remove ~100 orphaned screenshots, audit reports, logs from root Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
100 lines
4 KiB
TypeScript
100 lines
4 KiB
TypeScript
import { test, expect } from '@chromatic-com/playwright';
|
|
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);
|
|
});
|
|
}
|
|
});
|