63 lines
3.9 KiB
JavaScript
63 lines
3.9 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import test from 'node:test';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { parse } from '@babel/parser';
|
|
import postcss from 'postcss';
|
|
import { themeAnalysis } from './guard-theme-analysis.mjs';
|
|
|
|
const workspace = fileURLToPath(new URL('../', import.meta.url));
|
|
function walk(node, visitor, parent = null, field = null) {
|
|
if (!node || typeof node !== 'object') return;
|
|
if (node.type) visitor(node, parent, field);
|
|
for (const [key, value] of Object.entries(node)) {
|
|
if (['loc', 'start', 'end', 'comments', 'tokens', 'extra'].includes(key)) continue;
|
|
if (Array.isArray(value)) value.forEach(item => walk(item, visitor, node, key));
|
|
else if (value && typeof value === 'object') walk(value, visitor, node, key);
|
|
}
|
|
}
|
|
function analyze(edges, source) {
|
|
const issues = [];
|
|
const file = fileURLToPath(import.meta.url);
|
|
const result = themeAnalysis({ workspace, postcss, walk, selectedFile: () => true,
|
|
records: [{ file, edges, ast: parse(source, { sourceType: 'module' }) }],
|
|
add: (severity, code, file, node, message) => issues.push({ severity, code, message }),
|
|
});
|
|
return { ...result, issues };
|
|
}
|
|
test('OrgChart public CSS and ?url collect the same scoped defaults', () => {
|
|
const source = 'const values = "var(--hm-orgchart-current-gradient) var(--hm-orgchart-current-card-background) var(--hm-orgchart-current-border) var(--hm-orgchart-resolved-bg-surface)";';
|
|
const direct = analyze([{ spec: '@hm-design/org-chart/style.css', runtime: true }], source);
|
|
const shadow = analyze([{ spec: '@hm-design/org-chart/style.css?url', runtime: false }], source);
|
|
assert.deepEqual(direct.definitions, shadow.definitions);
|
|
assert.deepEqual(shadow.issues, []);
|
|
assert.equal(shadow.incomplete, false);
|
|
assert.ok(shadow.references.every(ref => ref.status === 'PASS' && ref.origin === 'PUBLIC'));
|
|
});
|
|
test('Disconnected OrgChart CSS cannot lend definitions to UI or another Story', () => {
|
|
const source = 'const value = "var(--hm-orgchart-current-gradient, red)";';
|
|
for (const edges of [[], [{ spec: '@hm-design/ui/theme.css', runtime: true }], [{ spec: '@hm-design/org-chart/style.css?raw', runtime: false }]]) {
|
|
assert.ok(analyze(edges, source).issues.some(issue => issue.code === 'TOKEN-001' && issue.severity === 'FAIL'));
|
|
}
|
|
});
|
|
test('Fallbacks and JS setProperty do not waive undeclared HM tokens', () => {
|
|
const result = analyze([{ spec: '@hm-design/org-chart/style.css?url', runtime: false }], 'el.style.setProperty("--hm-fake", "red"); const value = "var(--hm-fake, red)";');
|
|
assert.ok(result.issues.some(issue => issue.code === 'TOKEN-001' && issue.severity === 'FAIL'));
|
|
});
|
|
test('Shared UI declaration collection and unknown token policy remain intact', () => {
|
|
const result = analyze([{ spec: '@hm-design/ui/theme.css', runtime: true }], 'const value = "var(--hm-sem-fg-primary) var(--hm-missing, blue)";');
|
|
assert.equal(result.references.find(ref => ref.name === '--hm-sem-fg-primary').status, 'PASS');
|
|
assert.equal(result.references.find(ref => ref.name === '--hm-missing').status, 'FAIL');
|
|
});
|
|
test('All seven CSS company defaults and six Fixed gradients match approved presets', () => {
|
|
const css = fs.readFileSync(path.join(workspace, 'packages/org-chart/src/styles/color-presets.css'), 'utf8');
|
|
const presets = fs.readFileSync(path.join(workspace, 'packages/org-chart/src/company-color-presets.ts'), 'utf8');
|
|
for (const [id, color] of [['hanmac', '#CB2E28'], ['saman', '#F08300'], ['jangheon-industry', '#4580A6'], ['jangheon', '#1D418D'], ['ptc', '#84338E'], ['halla', '#0068B7'], ['baron', '#0C367F']]) {
|
|
assert.ok(presets.includes(`primary: '${color}'`));
|
|
assert.ok(css.includes(`var(--hm-orgchart-company-${id}, ${color})`));
|
|
}
|
|
const fixed = fs.readFileSync(path.join(workspace, 'packages/org-chart/src/core/style-presets.ts'), 'utf8');
|
|
for (const match of fixed.matchAll(/backgroundImage: '([^']+)'/g)) assert.ok(css.includes(match[1]));
|
|
});
|