// frontend/playwright/a11y.spec.ts — 3페이지 접근성 감사(라이트/다크) + 키보드 // color-contrast 제외(레퍼런스 액센트 팔레트가 디자인 정본) — 구조/시맨틱 WCAG 는 엄격. import AxeBuilder from "@axe-core/playwright"; import { expect, test } from "@playwright/test"; const AXE = (page: import("@playwright/test").Page) => new AxeBuilder({ page }).withTags(["wcag2a", "wcag2aa", "wcag21aa"]).disableRules(["color-contrast"]); const PAGES: [string, string][] = [ ["/dashboard", "아리 브리핑"], ["/inbox", "스마트 인박스"], ["/tasks", "리스크 레이더"], ]; for (const [path, marker] of PAGES) { test(`a11y(axe): ${path} — 위반 0건`, async ({ page }) => { await page.goto(path); await page.getByText(marker).first().waitFor(); const r = await AXE(page).analyze(); expect(r.violations, JSON.stringify(r.violations, null, 2)).toEqual([]); }); } test("다크 테마 대시보드 — 위반 0건 + 테마 영속", async ({ page }) => { await page.goto("/dashboard"); await page.getByText("아리 브리핑").waitFor(); await page.getByLabel("테마 전환").click(); await expect(page.locator("html")).toHaveAttribute("data-theme", "dark"); const r = await AXE(page).analyze(); expect(r.violations).toEqual([]); await page.reload(); await expect(page.locator("html")).toHaveAttribute("data-theme", "dark"); // localStorage 영속 }); test("키보드 내비: Tab 으로 포커스 이동 가능", async ({ page }) => { await page.goto("/dashboard"); await page.keyboard.press("Tab"); const focused = await page.evaluate(() => document.activeElement?.tagName); expect(focused).toBeTruthy(); });