- 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 产物装配与部署形态。
23 lines
1.5 KiB
JavaScript
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();
|