diff options
| author | cashmere <cashmere@autistici.org> | 2026-09-04 09:05:24 +0200 |
|---|---|---|
| committer | cashmere <cashmere@autistici.org> | 2026-09-04 09:05:24 +0200 |
| commit | 4f49b16079b27d7ce633619e4cddfdf2bffbc952 (patch) | |
| tree | c296c1e7f3c3e2f6859c6d3a1b1b208779b89679 /tools/copland/tests/visual.spec.mjs | |
| download | relic-master.tar.gz | |
Diffstat (limited to 'tools/copland/tests/visual.spec.mjs')
| -rw-r--r-- | tools/copland/tests/visual.spec.mjs | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/tools/copland/tests/visual.spec.mjs b/tools/copland/tests/visual.spec.mjs new file mode 100644 index 0000000..73559e1 --- /dev/null +++ b/tools/copland/tests/visual.spec.mjs @@ -0,0 +1,94 @@ +import AxeBuilder from "@axe-core/playwright"; +import { expect, test } from "@playwright/test"; + +const pages = [ + ["repository-list", "/"], + ["home", "/alpha/home"], + ["timeline", "/alpha/timeline"], + ["tree", "/alpha/tree?ci=tip"], + ["org-document", "/alpha/doc/tip/docs/org-support.org"], + ["org-wiki", "/alpha/wiki?name=Org%20Wiki"], + ["login", "/alpha/login"], +]; + +for (const colorScheme of ["light", "dark"]) { + for (const [name, path] of pages) { + test(`${name} is legible in ${colorScheme} mode`, async ({ page }) => { + await page.emulateMedia({ colorScheme }); + await page.goto(path); + await expect(page.locator("body")).toContainText("Copland"); + + const viewportOverflow = await page.evaluate( + () => document.documentElement.scrollWidth > document.documentElement.clientWidth, + ); + expect(viewportOverflow).toBe(false); + + let accessibilityScan = new AxeBuilder({ page }) + .withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]) + .disableRules(["html-has-lang"]) + .exclude(".submenu"); + if (name === "login") { + accessibilityScan = accessibilityScan.exclude("form"); + } + const accessibility = await accessibilityScan.analyze(); + expect(accessibility.violations).toEqual([]); + + const screenshotMasks = [page.locator(".site-footer span:last-child")]; + if (name === "login") { + screenshotMasks.push(page.locator("form")); + } + await expect(page).toHaveScreenshot(`${name}-${colorScheme}.png`, { + fullPage: true, + animations: "disabled", + mask: screenshotMasks, + maxDiffPixelRatio: 0.001, + }); + }); + } +} + +test.describe("mobile", () => { + test.use({ viewport: { width: 320, height: 720 } }); + + test("navigation remains usable", async ({ page }) => { + await page.goto("/alpha/timeline"); + await expect(page.locator(".site-brand")).toHaveText("Copland"); + await expect(page.locator(".mainmenu")).toBeVisible(); + const viewportOverflow = await page.evaluate( + () => document.documentElement.scrollWidth > document.documentElement.clientWidth, + ); + expect(viewportOverflow).toBe(false); + await expect(page).toHaveScreenshot("timeline-mobile.png", { + fullPage: true, + mask: [page.locator(".site-footer span:last-child")], + }); + }); + + test("Org documentation remains readable", async ({ page }) => { + await page.goto("/alpha/doc/tip/docs/org-support.org"); + await expect(page.locator(".org-document")).toBeVisible(); + await expect(page.locator(".org-toc")).toBeVisible(); + const viewportOverflow = await page.evaluate( + () => document.documentElement.scrollWidth > document.documentElement.clientWidth, + ); + expect(viewportOverflow).toBe(false); + await expect(page).toHaveScreenshot("org-document-mobile.png", { + fullPage: true, + mask: [page.locator(".site-footer span:last-child")], + }); + }); + + test("Org wiki remains readable", async ({ page }) => { + await page.goto("/alpha/wiki?name=Org%20Wiki"); + await expect(page.locator(".org-document")).toBeVisible(); + await expect(page.locator(".org-toc")).toBeVisible(); + const viewportOverflow = await page.evaluate( + () => document.documentElement.scrollWidth > document.documentElement.clientWidth, + ); + expect(viewportOverflow).toBe(false); + await expect(page).toHaveScreenshot("org-wiki-mobile.png", { + fullPage: true, + mask: [page.locator(".site-footer span:last-child")], + }); + }); +}); |
