61 lines
2.6 KiB
JavaScript
61 lines
2.6 KiB
JavaScript
/**
|
||
* semantic.ts self-test. 该模块必须零 import(Node 原生类型剥离直连 .ts,
|
||
* 同 tests/terminal-cwd.mjs 的约束)。锁三件事:
|
||
* 1) isLightTheme 边界(>0.5 亮度为浅);
|
||
* 2) 深色分支 = SEMANTIC 锚点原值(零回归锁定);
|
||
* 3) 浅色分支全部达标:正文/fg ≥4.5,语义基色 ≥3.0。
|
||
* Run: node tests/semantic-theme.mjs (must exit 0)
|
||
*/
|
||
import { isLightTheme, semanticVars, SEMANTIC } from '../src/renderer/src/theme/semantic.ts'
|
||
|
||
let failed = 0
|
||
const ok = (cond, msg) => {
|
||
console.log(` ${cond ? 'ok' : 'FAIL'}: ${msg}`)
|
||
if (!cond) failed += 1
|
||
}
|
||
|
||
console.log('isLightTheme:')
|
||
ok(isLightTheme('#ffffff') === true, '#ffffff is light')
|
||
ok(isLightTheme('#fafafa') === true, '#fafafa is light')
|
||
ok(isLightTheme('#fdf6e3') === true, '#fdf6e3 is light')
|
||
ok(isLightTheme('#1e1e1e') === false, '#1e1e1e is dark')
|
||
ok(isLightTheme('#282a36') === false, '#282a36 is dark')
|
||
|
||
console.log('dark branch locks anchors (zero regression):')
|
||
const dark = semanticVars({ background: '#1e1e1e', foreground: '#cccccc' }, false)
|
||
ok(dark['muted'] === SEMANTIC.muted, 'muted = anchor')
|
||
ok(dark['success'] === SEMANTIC.success, 'success = anchor')
|
||
ok(dark['danger'] === SEMANTIC.danger, 'danger = anchor')
|
||
ok(dark['warning'] === SEMANTIC.warning, 'warning = anchor')
|
||
ok(dark['info'] === SEMANTIC.info, 'info = anchor')
|
||
ok(dark['scrollbar'] === SEMANTIC.scrollbar, 'scrollbar = anchor')
|
||
ok(dark['shadow'] === SEMANTIC.shadow, 'shadow = anchor')
|
||
ok(dark['colorScheme'] === 'dark', 'colorScheme dark')
|
||
|
||
console.log('light branch meets ratios:')
|
||
for (const bg of ['#f6f8fa', '#fafafa', '#fdf6e3']) {
|
||
const v = semanticVars({ background: bg, foreground: '#383a42' }, true)
|
||
const L = (h) => {
|
||
const c = [1, 3, 5].map((i) => parseInt(h.slice(i, i + 2), 16) / 255)
|
||
.map((s) => (s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4))
|
||
return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2]
|
||
}
|
||
const cr = (a, b) => {
|
||
const x = L(a), y = L(b)
|
||
return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05)
|
||
}
|
||
for (const key of ['muted', 'textSecondary', 'successFg', 'dangerFg', 'warningFg', 'infoFg']) {
|
||
ok(cr(v[key], bg) >= 4.5, `${bg} ${key} ${v[key]} >= 4.5 (${cr(v[key], bg).toFixed(2)})`)
|
||
}
|
||
for (const key of ['success', 'danger', 'warning', 'info']) {
|
||
ok(cr(v[key], bg) >= 3, `${bg} ${key} ${v[key]} >= 3.0 (${cr(v[key], bg).toFixed(2)})`)
|
||
}
|
||
ok(v['colorScheme'] === 'light', `${bg} colorScheme light`)
|
||
}
|
||
|
||
if (failed > 0) {
|
||
console.error(`${failed} check(s) failed`)
|
||
process.exit(1)
|
||
}
|
||
console.log('semantic-theme: all ok')
|