import AxeBuilder from '@axe-core/playwright'; import { test, expect } from '@playwright/test'; // Accessibility coverage specifically for the briefwechsel thumbnail-row // layout. Seeds two persons + a bilateral document via the API so the page // reaches the results state (not the hero), then runs axe-core // (wcag2a + wcag2aa) across three viewports and two color schemes. const VIEWPORTS = [ { name: 'mobile', width: 375, height: 812 }, { name: 'tablet', width: 768, height: 1024 }, { name: 'desktop', width: 1280, height: 800 } ] as const; const THEMES = ['light', 'dark'] as const; let senderId: string; let receiverId: string; test.describe('Accessibility — /briefwechsel row layout', () => { test.beforeAll(async ({ request }) => { const timestamp = Date.now(); const senderRes = await request.post('/api/persons', { data: { firstName: 'A11y', lastName: `Sender-${timestamp}` } }); if (!senderRes.ok()) throw new Error(`Create sender failed: ${senderRes.status()}`); senderId = (await senderRes.json()).id; const receiverRes = await request.post('/api/persons', { data: { firstName: 'A11y', lastName: `Receiver-${timestamp}` } }); if (!receiverRes.ok()) throw new Error(`Create receiver failed: ${receiverRes.status()}`); receiverId = (await receiverRes.json()).id; const docRes = await request.post('/api/documents', { multipart: { title: 'A11y Test Brief', documentDate: '1950-06-15', senderId, receiverIds: receiverId } }); if (!docRes.ok()) throw new Error(`Create document failed: ${docRes.status()}`); }); for (const vp of VIEWPORTS) { for (const theme of THEMES) { test(`${vp.name} / ${theme} has no wcag2a/wcag2aa violations`, async ({ page }) => { await page.setViewportSize({ width: vp.width, height: vp.height }); await page.emulateMedia({ colorScheme: theme }); await page.goto( `/briefwechsel?senderId=${encodeURIComponent(senderId)}&receiverId=${encodeURIComponent(receiverId)}` ); await page.waitForSelector('[data-hydrated]'); // Assert we actually reached the row layout, not the hero — otherwise // the axe sweep silently scans the wrong DOM. await expect(page.getByTestId('conv-person-bar')).toBeVisible(); const results = await new AxeBuilder({ page }) .withTags(['wcag2a', 'wcag2aa']) .include('main') .analyze(); if (results.violations.length > 0) { const summary = results.violations .map((v) => `[${v.impact}] ${v.id}: ${v.description} (${v.nodes.length} node(s))`) .join('\n'); console.log( `\nAccessibility violations on briefwechsel (${vp.name}/${theme}):\n${summary}` ); } expect(results.violations).toEqual([]); }); } } });