dsh-structured 0.9.4 → 0.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,71 @@
1
+ import assert from 'node:assert/strict'
2
+ import { execSync } from 'node:child_process'
3
+ import { readFileSync, rmSync } from 'node:fs'
4
+ import { fileURLToPath, pathToFileURL } from 'node:url'
5
+ import test from 'node:test'
6
+
7
+ // CI runner 通常没有 ego-browser;缺失时跳过,不让环境差异把测试判成失败。
8
+ function egoAvailable() {
9
+ try {
10
+ execSync(process.platform === 'win32' ? 'where ego-browser' : 'command -v ego-browser', { stdio: 'ignore' })
11
+ return true
12
+ } catch {
13
+ return false
14
+ }
15
+ }
16
+
17
+ test('0.9.6 style:真实浏览器 computedStyle 与 800px 布局', { timeout: 120_000 }, (t) => {
18
+ if (!egoAvailable()) {
19
+ t.skip('ego-browser 不可用,跳过真实浏览器样式检查')
20
+ return
21
+ }
22
+ const source = readFileSync(new URL('../src/client.js', import.meta.url), 'utf8')
23
+ assert.doesNotMatch(source, /--ds-card-icon/)
24
+ const probe = fileURLToPath(new URL('./fixtures/style-probe.mjs', import.meta.url))
25
+ const resultPath = fileURLToPath(new URL('../artifacts/audit-0.9.6/style-result.json', import.meta.url))
26
+ const url = pathToFileURL(probe).href
27
+ rmSync(resultPath, { force: true })
28
+ execSync(`ego-browser nodejs -e "await import('${url}')"`, {
29
+ encoding: 'utf8',
30
+ stdio: ['ignore', 'pipe', 'pipe'],
31
+ timeout: 90_000,
32
+ })
33
+ const { style, narrow } = JSON.parse(readFileSync(resultPath, 'utf8'))
34
+ rmSync(resultPath, { force: true })
35
+
36
+ assert.equal(style.titleSize, '24px')
37
+ assert.equal(style.titleWeight, '700')
38
+ assert.equal(style.bodySize, '13.5px')
39
+ assert.equal(style.bodyLine, '21.6px')
40
+ assert.equal(style.dividerHeight, '1px')
41
+ assert.equal(style.dividerBackground, 'rgb(226, 232, 240)')
42
+ assert.equal(style.headerSize, '13px')
43
+ assert.equal(style.headerWeight, '700')
44
+ assert.equal(style.headerHeight, '38px')
45
+ assert.equal(style.bodyCellSize, '12.5px')
46
+ assert.equal(style.statusPillSize, '10px')
47
+ assert.equal(style.leadSize, '13px')
48
+ assert.equal(style.leadStrongSize, '14px')
49
+ assert.equal(style.leadStrongWeight, '700')
50
+ assert.equal(style.leadBorderTop, '0px')
51
+ assert.equal(style.leadBorderRight, '0px')
52
+ assert.equal(style.leadBorderBottom, '0px')
53
+ assert.equal(style.leadBorderLeft, '0px')
54
+ assert.equal(style.nextTitleSize, '16px')
55
+ assert.equal(style.nextTitleWeight, '700')
56
+ assert.equal(style.nextStepSize, '13px')
57
+ assert.equal(style.nextBackground, 'rgba(0, 0, 0, 0)')
58
+ assert.equal(style.nextBorderTop, '1px')
59
+ assert.equal(style.nextBorderRight, '0px')
60
+ assert.equal(style.nextBorderBottom, '0px')
61
+ assert.equal(style.nextBorderLeft, '0px')
62
+ assert.equal(style.triangleColor, 'rgb(194, 65, 12)')
63
+ assert.equal(style.triangleLeftWidth, '9px')
64
+ assert.equal(style.triangleTopWidth, '5px')
65
+ assert.equal(style.triangleBottomWidth, '5px')
66
+ assert.equal(style.darkTriangleColor, 'rgb(251, 146, 60)')
67
+ assert.ok(Math.abs(style.liLeft - style.labelLeft) <= 1, `next label/li delta ${style.liLeft - style.labelLeft}`)
68
+ assert.equal(style.cardIconBefore, 'none')
69
+ assert.equal(narrow.overflow, false)
70
+ assert.ok(narrow.docScrollWidth <= narrow.innerWidth)
71
+ })
@@ -3,6 +3,7 @@ import { readFileSync } from 'node:fs'
3
3
  import test from 'node:test'
4
4
  import { Config, statusText, THEMES } from '../src/index.js'
5
5
  import { checkThemeContrast, THEME_TOKENS } from '../scripts/theme-contrast.mjs'
6
+ import { checkHueSeparation } from '../scripts/theme-hue-distance.mjs'
6
7
 
7
8
  const value = (field) => (field && typeof field.get === 'function' ? field.get() : field)
8
9
 
@@ -14,7 +15,13 @@ test('0.9.0 Config:theme 默认 deepseek,三值可选', () => {
14
15
  assert.equal(value(Config({ defaultEnabled: false }).defaultEnabled), false)
15
16
  })
16
17
 
17
- test('0.9.1 Config:六个字段的默认值与显式值', () => {
18
+ test('0.9.8 accent/status hue 分离:12 项通过', () => {
19
+ const { results, failures } = checkHueSeparation()
20
+ assert.equal(failures.length, 0, JSON.stringify(failures, null, 2))
21
+ assert.equal(results.length, 12)
22
+ })
23
+
24
+ test('0.9.8 Config:六个字段的默认值与显式值', () => {
18
25
  const defaults = Config({})
19
26
  assert.equal(value(defaults.theme), 'deepseek')
20
27
  assert.equal(value(defaults.visual), true)
@@ -82,14 +89,6 @@ test('0.9.0 client:主题 token/暗色 selector/code token 存在,旧 select
82
89
  assert.doesNotMatch(client, /--dsw-alias-state-/)
83
90
  assert.match(client, /--ds-accent:#2563EB/)
84
91
  for (const theme of ['codex', 'anthropic']) assert.match(client, new RegExp(`data-dsh-structured-theme="${theme}"`))
85
- assert.match(client, /a\{color:var\(--ds-accent-text\)/)
86
- assert.match(client, /li::marker\{color:var\(--ds-accent-text\)/)
87
- assert.match(client, /p\[\$\{LEAD_ATTR\}="table"\] strong\{color:var\(--ds-accent-text\)/)
88
- assert.match(client, /color:var\(--ds-accent-text\);overflow-wrap:anywhere/)
89
- assert.match(client, /blockquote\[\$\{TONE_ATTR\}\]>p:first-child>strong:first-child\{color:var\(--ds-accent-text\)/)
90
- const narrow = client.slice(client.indexOf('@media (max-width:720px)'), client.indexOf('@media (prefers-reduced-motion'))
91
- assert.match(narrow, /table:not\(\[\$\{SKIP_ATTR\}\]\)/)
92
- assert.doesNotMatch(narrow, /\[class\*="_markdown_"\] table\{/)
93
92
  })
94
93
 
95
94
  test('0.9.1 主题 v2:三套 token 精确值与 accentText', () => {