100 lines
2.9 KiB
TypeScript
100 lines
2.9 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 a[href^="mailto:"]')).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([]);
|
|
});
|
|
}
|