test(frontend): e2e api/axe helpers
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import { expect, type Page } from "@playwright/test";
|
||||
import AxeBuilder from "@axe-core/playwright";
|
||||
|
||||
interface Waiver {
|
||||
page: string;
|
||||
rule: string;
|
||||
reason: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* critical/serious 违规的逐条豁免清单(spec S3):
|
||||
* 仅允许「属于将被 ② 阅读器改版重写的旧 chrome」的问题进这里,reason 必须写明归属。
|
||||
* 例:{ page: "reader-chrome", rule: "color-contrast", reason: "旧 rd-* chrome 配色,② 迁移 shadcn token 后移除本豁免" }
|
||||
*/
|
||||
const WAIVERS: Waiver[] = [];
|
||||
|
||||
export async function scanA11y(page: Page, name: string): Promise<void> {
|
||||
const results = await new AxeBuilder({ page }).withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]).analyze();
|
||||
|
||||
if (results.violations.length > 0) {
|
||||
console.log(
|
||||
`[axe:${name}]`,
|
||||
JSON.stringify(
|
||||
results.violations.map((v) => ({ id: v.id, impact: v.impact, nodes: v.nodes.length })),
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const blocking = results.violations.filter(
|
||||
(v) =>
|
||||
(v.impact === "critical" || v.impact === "serious") && !WAIVERS.some((w) => w.page === name && w.rule === v.id),
|
||||
);
|
||||
expect(
|
||||
blocking.map((v) => ({ id: v.id, impact: v.impact })),
|
||||
`${name} 存在未豁免的 critical/serious a11y 违规`,
|
||||
).toEqual([]);
|
||||
}
|
||||
Reference in New Issue
Block a user