feat(miniprogram): Token 常量生成脚本 + useCanvasTokens hook (E2-1 Phase 2)
- 新增 scripts/generate-tokens.ts 从 SCSS 解析 CSS 变量生成 token-values.ts - 新增 useCanvasTokens hook 供 Canvas 组件适老化/医生端切换 - vitest include 扩展覆盖 scripts/__tests__/ - 10 单元测试覆盖 SCSS 解析和变量替换
This commit is contained in:
97
apps/miniprogram/scripts/__tests__/generate-tokens.test.ts
Normal file
97
apps/miniprogram/scripts/__tests__/generate-tokens.test.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
parseTokensFromScss,
|
||||
parseScssVariables,
|
||||
resolveTokenValues,
|
||||
} from '../generate-tokens';
|
||||
|
||||
describe('parseScssVariables', () => {
|
||||
it('extracts SCSS variable declarations', () => {
|
||||
const scss = '$pri: #C4623A;\n$bg: #F5F0EB;';
|
||||
const vars = parseScssVariables(scss);
|
||||
expect(vars).toEqual({ pri: '#C4623A', bg: '#F5F0EB' });
|
||||
});
|
||||
|
||||
it('ignores comments and non-variable lines', () => {
|
||||
const scss = '// comment\n$pri: #C4623A;';
|
||||
const vars = parseScssVariables(scss);
|
||||
expect(vars).toEqual({ pri: '#C4623A' });
|
||||
});
|
||||
|
||||
it('handles values with spaces and units', () => {
|
||||
const scss = '$shadow-sm: 0 1px 4px rgba(45, 42, 38, 0.06);\n$r: 16px;';
|
||||
const vars = parseScssVariables(scss);
|
||||
expect(vars['shadow-sm']).toBe('0 1px 4px rgba(45, 42, 38, 0.06)');
|
||||
expect(vars['r']).toBe('16px');
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseTokensFromScss', () => {
|
||||
it('extracts --tk-* CSS variables from page selector', () => {
|
||||
const scss = `page {
|
||||
--tk-font-h1: 28px;
|
||||
--tk-font-body: 16px;
|
||||
}`;
|
||||
const tokens = parseTokensFromScss(scss, 'page');
|
||||
expect(tokens).toEqual({ 'font-h1': '28px', 'font-body': '16px' });
|
||||
});
|
||||
|
||||
it('extracts from class selector', () => {
|
||||
const scss = `.elder-mode {
|
||||
--tk-font-h1: 32px;
|
||||
}`;
|
||||
const tokens = parseTokensFromScss(scss, '.elder-mode');
|
||||
expect(tokens).toEqual({ 'font-h1': '32px' });
|
||||
});
|
||||
|
||||
it('captures SCSS variable references as-is for later resolution', () => {
|
||||
const scss = `page {
|
||||
--tk-pri: #{$pri};
|
||||
--tk-font-body: 16px;
|
||||
}`;
|
||||
const tokens = parseTokensFromScss(scss, 'page');
|
||||
expect(tokens['pri']).toBe('#{$pri}');
|
||||
expect(tokens['font-body']).toBe('16px');
|
||||
});
|
||||
|
||||
it('returns empty object when selector not found', () => {
|
||||
const scss = `page { --tk-font-h1: 28px; }`;
|
||||
const tokens = parseTokensFromScss(scss, '.nonexistent');
|
||||
expect(tokens).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveTokenValues', () => {
|
||||
it('replaces SCSS variable references with actual values', () => {
|
||||
const tokensScss = `page {
|
||||
--tk-pri: #{$pri};
|
||||
}`;
|
||||
const varsScss = '$pri: #C4623A;';
|
||||
const result = resolveTokenValues(tokensScss, varsScss, 'page');
|
||||
expect(result).toEqual({ pri: '#C4623A' });
|
||||
});
|
||||
|
||||
it('handles plain values without SCSS references', () => {
|
||||
const tokensScss = `page {
|
||||
--tk-card-radius: 16px;
|
||||
--tk-font-body: 16px;
|
||||
}`;
|
||||
const varsScss = '$r: 16px;';
|
||||
const result = resolveTokenValues(tokensScss, varsScss, 'page');
|
||||
expect(result['card-radius']).toBe('16px');
|
||||
expect(result['font-body']).toBe('16px');
|
||||
});
|
||||
|
||||
it('handles multiple variable references', () => {
|
||||
const tokensScss = `page {
|
||||
--tk-pri: #{$pri};
|
||||
--tk-pri-l: #{$pri-l};
|
||||
--tk-font-body: 16px;
|
||||
}`;
|
||||
const varsScss = '$pri: #C4623A;\n$pri-l: #F0DDD4;';
|
||||
const result = resolveTokenValues(tokensScss, varsScss, 'page');
|
||||
expect(result['pri']).toBe('#C4623A');
|
||||
expect(result['pri-l']).toBe('#F0DDD4');
|
||||
expect(result['font-body']).toBe('16px');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user