Files
MailUI4Agents/client/electron/test/manual/accent-verify.mjs

85 lines
4.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 强调色可见性验收:真实渲染 + 取实际计算色 + 算 WCAG 对比度。
*
* 结构性断言test/theme.test.mjs只能保证变量存在、档位达标
* 「按钮到底看得见吗」必须在真浏览器里量 —— 上一次那个 bug 正是
* 所有静态检查都过、只有肉眼能发现。
*/
import { openApp, WIDE } from './narrow-probe-helper.mjs';
const srgb = c => { c /= 255; return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4; };
const L = ([r, g, b]) => 0.2126 * srgb(r) + 0.7152 * srgb(g) + 0.0722 * srgb(b);
const ratio = (a, b) => { const l1 = L(a), l2 = L(b); const [h, o] = l1 > l2 ? [l1, l2] : [l2, l1]; return (h + 0.05) / (o + 0.05); };
const parse = s => (s.match(/\d+/g) || []).slice(0, 3).map(Number);
// 把一批强调色类名注入页面,量它们的实际计算值
// hover 档bg-red-700 / bg-blue-700不在这里源码里它们只以 `hover:` 变体
// 出现Tailwind 因此不生成基础类 —— 探它会得到透明背景,那是探针的假阳性
// 而不是真 bug。它们由 theme.test.mjs 的档位断言覆盖(--s-* 两模式同值)。
const PROBES = [
// [类名组合, 说明, 期望最低对比度]
['bg-red-600 text-white', '危险实心按钮(确认归档 / 删除)', 3.0],
['bg-red-500 text-white', '未读徽标', 3.0],
['bg-green-600 text-white', '同意按钮', 3.0],
['bg-orange-700 text-white', '待决策徽标', 4.5],
['bg-blue-600 text-white', '主按钮', 4.5],
['bg-red-50 text-red-600', '错误提示条', 4.5],
['bg-red-50 text-red-700', '危险区块文字', 4.5],
['bg-green-50 text-green-700', '成功提示条', 4.5],
['bg-orange-100 text-orange-700', '橙色 chip', 4.5],
['bg-amber-100 text-amber-700', '警告 chip', 4.5],
['bg-amber-50 text-amber-800', '警告条', 4.5],
['bg-yellow-100 text-yellow-700', '黄色 chip', 4.5],
['bg-blue-50 text-blue-700', '信息条', 4.5],
['bg-red-100 text-red-700', '红色 chip', 4.5],
['bg-orange-200 text-orange-800', '深橙 chip', 4.5],
['bg-white text-gray-900', '卡片正文', 4.5],
['bg-white text-gray-500', '卡片次要文字', 4.5],
];
const { browser, page } = await openApp(WIDE);
let fail = 0;
for (const mode of ['light', 'dark']) {
await page.evaluate(m => {
document.documentElement.classList.toggle('dark', m === 'dark');
let host = document.getElementById('__probe');
if (host) host.remove();
host = document.createElement('div');
host.id = '__probe';
host.style.position = 'fixed';
host.style.top = '0';
host.style.left = '0';
host.style.zIndex = '99999';
document.body.appendChild(host);
}, mode);
console.log(`\n─── ${mode === 'dark' ? '深色' : '浅色'} ───`);
for (const [cls, label, min] of PROBES) {
const got = await page.evaluate(c => {
const host = document.getElementById('__probe');
host.innerHTML = `<span id="__p" class="${c}">测试</span>`;
const el = document.getElementById('__p');
const s = getComputedStyle(el);
return { bg: s.backgroundColor, fg: s.color };
}, cls);
// 透明背景 = 声明失效(正是上次那个 bug 的指纹)
const transparent = /rgba\(0,\s*0,\s*0,\s*0\)|transparent/.test(got.bg);
if (transparent) {
console.log(` 失败 ${label} — 背景透明(${cls} 的 background-color 声明失效)`);
fail++;
continue;
}
const r = ratio(parse(got.fg), parse(got.bg));
const ok = r >= min;
if (!ok) fail++;
console.log(` ${ok ? '通过' : '失败'} ${label.padEnd(22)} ${r.toFixed(2)}:1 (需 ${min}) ${got.bg} / ${got.fg}`);
}
}
await page.evaluate(() => document.getElementById('__probe')?.remove());
await browser.close();
console.log(fail ? `\n!! ${fail} 项不达标` : '\n全部达标');
process.exit(fail ? 1 : 0);