Files
Portfolio/tests/browser/accessibility-axe.spec.ts

100 lines
3.0 KiB
TypeScript

import AxeBuilder from "@axe-core/playwright";
import type { Page } from "@playwright/test";
import { expect, test } from "../helpers/serve-dist";
type AccessibilityState =
| "default"
| "audio-running"
| "static"
| "reduced-motion"
| "media-failure"
| "missing-social";
const states: readonly AccessibilityState[] = [
"default",
"audio-running",
"static",
"reduced-motion",
"media-failure",
"missing-social",
];
async function enterState(
page: Page,
distUrl: string,
state: AccessibilityState,
): Promise<void> {
if (state === "reduced-motion") {
await page.emulateMedia({ reducedMotion: "reduce" });
}
if (state === "media-failure") {
await page.addInitScript(() => {
const nativeGetContext = HTMLCanvasElement.prototype.getContext;
Object.defineProperty(HTMLCanvasElement.prototype, "getContext", {
configurable: true,
value(
this: HTMLCanvasElement,
contextId: string,
options?: unknown,
): RenderingContext | null {
if (
contextId === "webgl" ||
contextId === "webgl2" ||
contextId === "experimental-webgl"
) {
return null;
}
return Reflect.apply(nativeGetContext, this, [
contextId,
options,
]) as RenderingContext | null;
},
});
});
}
await page.goto(distUrl, { waitUntil: "domcontentloaded" });
if (state === "audio-running") {
await page.getByRole("button", { name: "PLAY SOUNDTRACK" }).click();
await expect(
page.getByRole("button", { name: "Mute sound" }),
).toBeVisible();
} else if (state === "static") {
await page.getByRole("button", { name: "Drive settings" }).click();
await page.getByLabel("Quality control").selectOption("static");
await expect(page.getByRole("status")).toContainText("Motion: static");
} else if (state === "reduced-motion") {
await page.getByRole("button", { name: "Drive settings" }).click();
await expect(page.getByRole("status")).toContainText(
"reduced motion requested",
);
} else if (state === "media-failure") {
await expect(page.locator(".journey-world")).toHaveAttribute(
"data-scene-state",
"failed",
);
} else if (state === "missing-social") {
await page.locator('#contact a[target="_blank"]').evaluateAll((links) => {
for (const link of links) link.closest("li")?.remove();
});
await expect(page.locator('#contact a[target="_blank"]')).toHaveCount(0);
await expect(page.locator('#contact :is(a, summary):text-is("Email Me")')).toBeVisible();
}
}
for (const state of states) {
test(`${state} has no WCAG 2.2 A or AA axe violations`, async ({
page,
distUrl,
}) => {
await enterState(page, distUrl, state);
const result = await new AxeBuilder({ page })
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"])
.analyze();
expect(result.violations).toEqual([]);
});
}