who_need_help/e2e/tests/accessibility-resilience.spec.ts

153 lines
5.2 KiB
TypeScript

import AxeBuilder from "@axe-core/playwright";
import { expect, test } from "@playwright/test";
import { newIsolatedContext, projectEmail, registerAndConfirm } from "./helpers";
const publicAccessibilityPaths = [
"/",
"/safety",
"/users/log-in",
"/users/register",
"/support",
"/account/delete",
"/legal/content-removal",
"/legal/take-it-down",
];
async function expectAccessible(page: import("@playwright/test").Page): Promise<void> {
const results = await new AxeBuilder({ page }).analyze();
expect(
results.violations,
results.violations
.map(
(violation) =>
`${violation.id}: ${violation.help}\n${violation.nodes
.map((node) => ` ${node.target.join(" ")}: ${node.failureSummary}`)
.join("\n")}`,
)
.join("\n\n"),
).toEqual([]);
}
test("public pages are accessible by keyboard in light and dark themes", async ({ browser }) => {
const context = await newIsolatedContext(browser);
const page = await context.newPage();
await page.goto("/");
await page.keyboard.press("Tab");
await expect(page.getByRole("link", { name: "Skip to main content" })).toBeFocused();
await page.keyboard.press("Enter");
await expect(page.locator("#main-content")).toBeFocused();
for (const theme of ["light", "dark"] as const) {
await page.getByRole("button", { name: `Use ${theme} theme` }).click();
await expect(page.locator("html")).toHaveAttribute("data-theme", theme);
for (const path of publicAccessibilityPaths) {
await page.goto(path);
await expectAccessible(page);
}
}
await context.close();
});
test("public navigation does not overflow narrow or wide viewports", async ({ browser }) => {
for (const viewport of [
{ width: 360, height: 800 },
{ width: 768, height: 1024 },
{ width: 1030, height: 900 },
{ width: 1440, height: 900 },
]) {
const context = await newIsolatedContext(browser);
const page = await context.newPage();
await page.setViewportSize(viewport);
for (const path of ["/", "/support", "/legal/content-removal", "/legal/take-it-down"]) {
await page.goto(path);
const dimensions = await page.evaluate(() => ({
clientWidth: document.documentElement.clientWidth,
scrollWidth: document.documentElement.scrollWidth,
}));
expect(dimensions.scrollWidth, `${path} overflowed at ${viewport.width}px`).toBeLessThanOrEqual(
dimensions.clientWidth,
);
}
await page.goto("/");
await expect(page.getByRole("navigation", { name: "Primary navigation" })).toBeVisible();
await expect(page.locator("body > header")).toHaveCount(1);
await expect(page.locator("body > nav[aria-label='Account and language']")).toHaveCount(0);
if (viewport.width < 1280) {
const menuButton = page.locator("summary[aria-label='Primary navigation']");
await expect(menuButton).toBeVisible();
await menuButton.click();
await expect(page.getByRole("link", { name: "Requests", exact: true })).toBeVisible();
await expect(page.getByRole("link", { name: "Activities", exact: true })).toBeVisible();
await expect(page.getByRole("link", { name: "Categories", exact: true })).toBeVisible();
await expect(page.getByRole("link", { name: "Helpers", exact: true })).toBeVisible();
await expect(page.getByRole("link", { name: "English", exact: true })).toBeVisible();
await expect(page.getByRole("link", { name: "Log in", exact: true })).toBeVisible();
const openDimensions = await page.evaluate(() => ({
clientWidth: document.documentElement.clientWidth,
scrollWidth: document.documentElement.scrollWidth,
}));
expect(openDimensions.scrollWidth).toBeLessThanOrEqual(openDimensions.clientWidth);
} else {
await expect(page.locator("summary[aria-label='Primary navigation']")).toBeHidden();
await expect(page.getByRole("link", { name: "Requests", exact: true })).toBeVisible();
await expect(page.getByRole("link", { name: "English", exact: true })).toBeVisible();
await expect(page.getByRole("link", { name: "Register", exact: true })).toBeVisible();
await expect(page.getByRole("link", { name: "Log in", exact: true })).toBeVisible();
}
await context.close();
}
});
test("authenticated core workflows remain accessible on a phone viewport", async ({
browser,
request,
}, testInfo) => {
const user = await registerAndConfirm(
browser,
request,
projectEmail("mobile-accessibility", testInfo.project.name),
"Mobile accessibility",
);
await user.page.setViewportSize({ width: 390, height: 844 });
for (const path of [
"/requests",
"/requests/new",
"/activities",
"/notifications",
"/profile",
"/users/settings",
"/support/requests",
"/reports",
]) {
await user.page.goto(path);
await expectAccessible(user.page);
const dimensions = await user.page.evaluate(() => ({
clientWidth: document.documentElement.clientWidth,
scrollWidth: document.documentElement.scrollWidth,
}));
expect(dimensions.scrollWidth, `${path} overflowed at 390px`).toBeLessThanOrEqual(
dimensions.clientWidth,
);
}
await user.context.close();
});