Files
novalon-website/docs/acceptance/2026-09-21-axe/probe-axe-rule-coverage.mjs
T
zhangxiang a0328a623f chore(qa): 验收台账与证据入库 + 构建/部署配置同步
- docs/acceptance/qa-tracker.md:跨周期缺陷单一真源台账(§7=第五轮)。
- 周期 1/2 + iPhone SE/axe 验收证据目录、ACCEPTANCE_REVIEW 快照入库。
- 同步 README/CONTEXT/CLAUDE/DESIGN/testing/deployment/lessons-learned 口径;
  next.config/Dockerfile/nginx/Jenkinsfile/docker-compose/sentry/prisma 对齐
  standalone 产物装配与部署形态。
2026-09-28 10:48:09 +08:00

23 lines
1.5 KiB
JavaScript

import { chromium } from 'playwright';
import path from 'path';
const ROOT = '/Users/zhangxiang/Codes/Novalon/novalon-website';
const TAGS = ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'];
// 每条规则各造一个必然违规的最小节点(正对照)+ 一个正常页(负对照)
const cases = {
'autocomplete-valid': '<form><label for=x>n</label><input id=x autocomplete="bogus-value"></form>',
'presentation-role-conflict': '<div role="button" aria-label="x" tabindex="0" style="display:none">h</div><img alt="" role="presentation" tabindex="0" src="data:,"><h1>t</h1><main>m</main>',
'svg-img-alt': '<svg role="img" width="10" height="10"><rect width="10" height="10"></rect></svg><h1>t</h1><main>m</main>',
};
const b = await chromium.launch();
for (const [rule, html] of Object.entries(cases)) {
const p = await b.newPage();
await p.setContent(`<!doctype html><html lang="zh-CN"><head><title>t</title></head><body><main>${html}</main></body></html>`);
await p.addScriptTag({ path: path.join(ROOT, 'node_modules/axe-core/axe.min.js') });
const res = await p.evaluate((tags) => window.axe.run(document, { runOnly: { type: 'tag', values: tags } }), TAGS);
const v = res.violations.find((x) => x.id === rule);
const ran = [...res.violations, ...res.passes, ...res.incomplete].some((x) => x.id === rule);
console.log(`${rule.padEnd(28)} tagIncluded=${ran ? 'YES' : 'NO '} violation=${v ? v.nodes.length + ' nodes' : '0'}`);
await p.close();
}
await b.close();