import AxeBuilder from '@axe-core/playwright'; import { expect, test, type Page } from '@playwright/test'; import { contextForUser } from './helpers'; /** * Teich-Akzent (issue #186, ADR 0018 Stufe C): der Akzent eines Teichs * färbt NUR die Teich-Inhalte (PondThemeScope), das App-Chrome behält den * Akzent der Betrachtenden; je Modus wird abgeleitet. Der Spec setzt das * Theme des content-fixtures-Teichs per API und RÄUMT ES AM ENDE WIEDER AB * (Fixtures sind pack-übergreifend geteilt). */ const BASE = process.env.E2E_BASE_URL ?? 'http://localhost:5173'; const POND = 'content-fixtures'; const ACCENT = '#6d4fa0'; // iris-violet: besteht hell verbatim, dunkel wird abgeleitet const accentAt = (page: Page, selector: string) => page.evaluate( (sel) => getComputedStyle(document.querySelector(sel)!).getPropertyValue('--color-accent').trim(), selector, ); test('pond accent colors the pond content but not the app chrome', async ({ browser }) => { const context = await contextForUser(browser, BASE, 'fixture-user'); const page = await context.newPage(); await page.emulateMedia({ colorScheme: 'light' }); const pond = await page.request.get(`${BASE}/api/v1/ponds/${POND}`); expect(pond.ok()).toBe(true); const pondId = ((await pond.json()) as { id: string }).id; try { const patch = await page.request.patch(`${BASE}/api/v1/ponds/${pondId}`, { data: { theme: { accent: ACCENT } }, }); expect(patch.ok()).toBe(true); await page.goto(`/p/${POND}/every-element`); await page.locator('.pond-theme-scope').waitFor(); // Scope-Grenze: Inhalt trägt den Teich-Akzent, die TopBar den Default. expect(await accentAt(page, '.pond-theme-scope')).toBe(ACCENT); expect(await accentAt(page, '.topbar')).toBe('#2f6f4f'); // Moduswechsel leitet neu ab: dunkel bekommt einen helleren Wert. await page.locator('.topbar__theme').click(); // system -> light await page.locator('.topbar__theme').click(); // light -> dark const darkAccent = await accentAt(page, '.pond-theme-scope'); expect(darkAccent).not.toBe(ACCENT); expect(darkAccent).toMatch(/^#[0-9a-f]{6}$/); expect(await accentAt(page, '.topbar')).not.toBe(ACCENT); // Die Teich-Einstellungen (mit neuer Akzent-Sektion) bleiben axe-sauber. await page.goto(`/p/${POND}/settings`); await page.locator('input[name="pond-theme-accent"]').first().waitFor(); const results = await new AxeBuilder({ page }) .withTags(['wcag2a', 'wcag21a', 'wcag2aa', 'wcag21aa']) .analyze(); expect( results.violations.map((v) => ({ rule: v.id, help: v.help })), 'axe auf den Teich-Einstellungen', ).toEqual([]); } finally { await page.request.patch(`${BASE}/api/v1/ponds/${pondId}`, { data: { theme: { accent: null } }, }); } await context.close(); });