fix(#118): resolve wcag2a/wcag2aa violations found by axe-core suite
Some checks failed
CI / Unit & Component Tests (push) Has been cancelled
CI / Backend Unit Tests (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled

- Add <svelte:head><title> to home, persons, admin, login, and error pages
- Add aria-label to hidden file input in DropZone (sr-only but must be labelled)
- Add aria-label to search input in SearchFilterBar
- Create +error.svelte so error pages always have a document title
- axe-core spec: add buildAxe() helper, disable color-contrast (brand palette, tracked separately)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-03-28 17:29:47 +01:00
parent f9236cc575
commit 9a4e088de9
8 changed files with 39 additions and 5 deletions

View File

@@ -6,9 +6,9 @@ import { test, expect } from '@playwright/test';
* Authenticated pages use the stored admin session from playwright.config.ts.
* The login page test overrides to an unauthenticated context.
*
* On first run: if violations are found they are logged with full details so
* that they can be either fixed or explicitly excluded here with a comment
* explaining the reason.
* Known exclusion:
* color-contrast — brand palette (ink-3, text-ink/60) does not meet AA contrast
* ratios. Requires a design review with Leonie before fixing. Tracked separately.
*/
const AUTHENTICATED_PAGES = [
@@ -17,13 +17,17 @@ const AUTHENTICATED_PAGES = [
{ name: 'admin', path: '/admin' }
];
function buildAxe(page: Parameters<typeof AxeBuilder>[0]['page']) {
return new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa']).disableRules(['color-contrast']);
}
test.describe('Accessibility — authenticated pages', () => {
for (const { name, path } of AUTHENTICATED_PAGES) {
test(`${name} page has no critical wcag2a/wcag2aa violations`, async ({ page }) => {
await page.goto(path);
await page.waitForSelector('[data-hydrated]');
const results = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa']).analyze();
const results = await buildAxe(page).analyze();
if (results.violations.length > 0) {
const summary = results.violations
@@ -44,7 +48,7 @@ test.describe('Accessibility — login page', () => {
await page.goto('/login');
await expect(page.getByLabel('Benutzername')).toBeVisible();
const results = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa']).analyze();
const results = await buildAxe(page).analyze();
if (results.violations.length > 0) {
const summary = results.violations