import { test, expect } from "@playwright/test" import axe from "axe-core" import { emptyAlerts, emptyOutbox } from "./fixtures/alerts" import { certificateState } from "./fixtures/certificates" import { state as containerState } from "./fixtures/containers" import { server } from "./fixtures/users" for (const theme of ["dark", "light"] as const) for (const width of [1280, 320]) { for (const path of ["alerts", "certificates", "containers", "filters", "filters-error", "uptime"]) { test(`Operational accessibility ${path} ${theme} ${width}`, async ({ page }) => { await page.setViewportSize({ width, height: 1000 }) await page.addInitScript(theme => localStorage.setItem("rl-theme", theme), theme) const writes: string[] = [] await page.route("**/health", route => route.fulfill({ json: { ok: true } })) await page.route("**/api/**", route => { const url = new URL(route.request().url()).pathname if (route.request().method() !== "GET") writes.push(url) if (path === "filters-error" && url === "/api/filters/rules") return route.fulfill({ status: 503, json: { error: "Fixture unavailable" } }) const json = url === "/api/auth/config" ? { required: false } : url === "/api/servers" ? [{ ...server, type: "home-router" }] : url === "/api/certificates/state" ? certificateState([]) : url === "/api/certificates/renew-settings" ? { enabled: true, intervalSec: 300, renewBeforeDays: 30 } : url === "/api/containers/state" ? containerState([]) : url === "/api/alerts" ? emptyAlerts : url === "/api/alerts/outbox" ? emptyOutbox : url === "/api/uptime/speed-probes" ? { probes: [] } : url === "/api/uptime/speed-test/runs" ? { runs: [] } : url === "/api/uptime/probes" ? { probes: [] } : url === "/api/filters/rules" ? { rulesets: [{ serverId: "1", rules: [] }], greTunnels: [], live: true } : url === "/api/filters/gre-tunnels" ? { tunnels: [] } : url === "/api/recursive-routes" ? { routes: [] } : {} return route.fulfill({ json }) }) await page.goto("/" + (path === "filters-error" ? "filters" : path)) await expect(page.locator("main").first()).toBeVisible() if (path === "certificates") await expect(page.getByText("Включено", { exact: true })).toBeVisible() if (path === "alerts") await expect(page.getByText("Правила не найдены", { exact: true })).toBeVisible() if (path === "filters-error") await expect(page.getByRole("alert").filter({ hasText: "Не удалось загрузить Filters" })).toBeVisible() await page.evaluate(() => document.fonts.ready) // Audit settled colours, after provider hydration and transitions. await page.waitForTimeout(900) await page.addScriptTag({ content: axe.source }) const violations = await page.evaluate(async () => (window as unknown as { axe: typeof axe }).axe.run(document, { runOnly: { type: "tag", values: ["wcag2a", "wcag2aa", "wcag21aa"] }, })) expect(violations.violations).toEqual([]) expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true) if (path === "certificates") { const blocks = page.getByRole("region", { name: /^Команды RouterOS:/ }) await expect(blocks).toHaveCount(3) for (const block of await blocks.all()) { await block.focus() await expect(block).toBeFocused() if (await block.evaluate(el => el.scrollWidth > el.clientWidth + 1)) { await block.press("ArrowRight") await expect.poll(() => block.evaluate(el => el.scrollLeft)).toBeGreaterThan(0) } } } expect(writes).toEqual([]) }) } }