Files
novalon-website/scripts/audit/contact-diag.mjs
T
zhangxiang 09ff3e026b chore(audit): add reusable dogfood UI/UX/UE audit toolkit and 2026-09-01 report
新增可复用的全站 dogfood 审计工具链(Playwright,31 路由约 2 分钟跑完):

- scripts/audit/ui-audit.mjs —— 主审计器。9 维自动化探针:对比度(WCAG
  相对亮度 + alpha 合成 + 大文本 3:1 / 小文本 4.5:1)、横向溢出、触控目标
  (WCAG 2.2 AA 2.5.8 24x24)、img alt、标题层级、form label、文本截断、
  颜色频次(品牌红覆盖)、性能(LCP + CLS)。支持多视口采集与 P1/P2/P3 自动分级。
- scripts/audit/audit-fullpage.mjs —— 核心页 fullPage 长图(首屏看不全叙事结构)
- scripts/audit/verify-tabbar.mjs —— 移动端 Tab bar 遮挡修复验证
- scripts/audit/contact-diag.mjs —— 单页诊断(console/pageerror/requestfailed 捕获)

防刷绿机制:对比度探针命中 aria-hidden 祖先时跳过,但累计 decorativeSkipped
让豁免量可见;触控探针把 aria-hidden 内的可聚焦元素计入 ariaHiddenFocusable
单独上报,不静默跳过。

已知盲区(需在报告中人工补判):effectiveBg 遇到渐变或图片背景返回 unknown
并跳过整节点 —— 详情页 hero 的装饰数字因此从未被自动报出。

.gitignore 增加 dogfood-ui-audit/(采集产物单轮可达 39MB,只提交脚本与报告)。

Refs: UI_UX_UE_AUDIT_2026-09-01.md
2026-09-20 11:50:58 +08:00

19 lines
1.1 KiB
JavaScript

import { chromium } from 'playwright';
const b = await chromium.launch({ headless: true });
const ctx = await b.newContext({ viewport: { width: 1440, height: 900 } });
const p = await ctx.newPage();
p.on('console', m => console.log(`[${m.type()}]`, m.text().slice(0, 300)));
p.on('pageerror', e => console.log('[PAGEERROR]', e.message.slice(0, 400)));
p.on('requestfailed', r => console.log('[REQFAIL]', r.url().slice(0, 120), r.failure()?.errorText));
await p.goto('http://localhost:3000/contact', { waitUntil: 'networkidle', timeout: 60000 }).catch(e => console.log('goto err', e.message.slice(0, 100)));
await p.waitForTimeout(3000);
const info = await p.evaluate(() => ({
bodyLen: document.body.innerHTML.length,
bodyKids: document.body.children.length,
h: document.documentElement.scrollHeight,
forms: document.querySelectorAll('form').length,
inputs: document.querySelectorAll('input,textarea,select').length,
main: document.querySelector('main')?.outerHTML.slice(0, 600) || 'NO main',
})).catch(e => ({ err: e.message }));
console.log('STATE', JSON.stringify(info, null, 2));
await b.close();