Wave 0 of the design-integration plan. Six new test files at tests/build/ and tests/i18n/ pin the contracts that later waves will GREEN: - tokens-adopted.test.ts (4 cases): src/shared/tokens.css exists + parses; src/popup/style.css @imports it; popup/style.css has zero hex literals; welcome.css conditional check. - fonts-present.test.ts: 7 required WOFF2 faces (Lora normal + Plex Sans ×4 + Plex Mono ×2) + LICENSE-Lora + LICENSE-IBM-Plex + README + optional Lora-Italic (A5 verify-at-execute). - icons-present.test.ts (15 cases across 3 sizes): existence, size FLOOR per assets-spec.md, PNG signature, dimensions, color-type byte === 6 (RGBA — RED until Wave 2 rsvg-convert overwrites the 16-bit-RGB placeholders). - no-remote-fonts.test.ts: production dist/ contains zero fonts.googleapis.com / https://fonts / googleapis substrings (MV3 CSP self-host invariant T-01-12-01). - manifest-i18n.test.ts (10 cases): manifest:name === '__MSG_extName__', :description === '__MSG_extDesc__', :default_locale === 'en', :action.default_title === '__MSG_tooltipOff__'; _locales/{en,ru}/ messages.json carry D-07 + D-08 canonical strings. - locale-parity.test.ts (4 cases): ru→en parity, en→ru symmetric, non-empty .message strings (RESEARCH Pitfall 4 mitigation). Current polarity: 29 RED + 18 GREEN across the 6 new files (placeholders already clear dim+size floors; no-remote-fonts vacuous-GREEN since tokens.css doesn't yet exist with remote URLs). Existing 100/100 vitest baseline preserved (verified SKIP_BUILD=1 npx vitest run). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
78 lines
3.5 KiB
TypeScript
78 lines
3.5 KiB
TypeScript
// tests/build/tokens-adopted.test.ts — Plan 01-12 Wave 0 RED unit test.
|
|
//
|
|
// Asserts that the canonical token system (src/shared/tokens.css) exists
|
|
// and is adopted by src/popup/style.css with ZERO hex literals remaining.
|
|
//
|
|
// Polarity at Wave 0 land:
|
|
// (a) GREEN if src/shared/tokens.css already exists (will be RED until
|
|
// Wave 1 Task 2 lands the canonical copy).
|
|
// (b) RED until Wave 4 Task 1 migrates src/popup/style.css to @import
|
|
// tokens.css and replaces hex literals with var(--mks-*) references.
|
|
// (c) RED until Wave 4 Task 1 removes every #[0-9a-fA-F]{3,8} match
|
|
// from src/popup/style.css (loom-palette adoption via tokens).
|
|
//
|
|
// References:
|
|
// - Plan 01-12 §interfaces (.mks-word definition, R2 Lora substitution)
|
|
// - RESEARCH §1 + §9 (per-surface mini-tokens anti-pattern; collapse
|
|
// into canonical src/shared/tokens.css)
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
import { existsSync, readFileSync } from 'node:fs';
|
|
import { resolve as resolvePath } from 'node:path';
|
|
|
|
const TOKENS_CSS_PATH = resolvePath(process.cwd(), 'src/shared/tokens.css');
|
|
const POPUP_STYLE_PATH = resolvePath(process.cwd(), 'src/popup/style.css');
|
|
const WELCOME_STYLE_PATH = resolvePath(process.cwd(), 'src/welcome/welcome.css');
|
|
const HEX_LITERAL_REGEX = /#[0-9a-fA-F]{3,8}\b/g;
|
|
const TOKENS_IMPORT_REGEX = /@import\s+["']\.\.\/shared\/tokens\.css["']/;
|
|
|
|
describe('Plan 01-12: tokens.css adoption (canonical token system)', () => {
|
|
it('(a) src/shared/tokens.css exists + parses as readable CSS', () => {
|
|
expect(
|
|
existsSync(TOKENS_CSS_PATH),
|
|
`Expected src/shared/tokens.css at ${TOKENS_CSS_PATH} (RED until Wave 1 Task 2)`,
|
|
).toBe(true);
|
|
const css = readFileSync(TOKENS_CSS_PATH, 'utf8');
|
|
expect(css.length, 'tokens.css must be non-empty').toBeGreaterThan(100);
|
|
expect(css, 'tokens.css must declare :root with --mks-* tokens').toMatch(/:root\s*\{/);
|
|
expect(css, 'tokens.css must include --mks-font-display token').toMatch(/--mks-font-display\s*:/);
|
|
});
|
|
|
|
it('(b) src/popup/style.css imports ../shared/tokens.css', () => {
|
|
expect(existsSync(POPUP_STYLE_PATH), 'src/popup/style.css must exist').toBe(true);
|
|
const css = readFileSync(POPUP_STYLE_PATH, 'utf8');
|
|
expect(
|
|
TOKENS_IMPORT_REGEX.test(css),
|
|
`Expected @import '../shared/tokens.css' in src/popup/style.css (RED until Wave 4 Task 1)`,
|
|
).toBe(true);
|
|
});
|
|
|
|
it('(c) src/popup/style.css has ZERO hex color literals (loom palette via var(--mks-*))', () => {
|
|
const css = readFileSync(POPUP_STYLE_PATH, 'utf8');
|
|
const matches = css.match(HEX_LITERAL_REGEX) ?? [];
|
|
expect(
|
|
matches.length,
|
|
matches.length === 0
|
|
? 'unreachable'
|
|
: `Expected 0 hex literals in src/popup/style.css; got ${matches.length}: ${matches.join(', ')}\n` +
|
|
`Replace each with var(--mks-*) per D-04 loom palette (Wave 4 Task 1).`,
|
|
).toBe(0);
|
|
});
|
|
|
|
it('(d) src/welcome/welcome.css — if present, has ZERO hex literals (Plan 01-10 conditional)', () => {
|
|
// Conditional: only enforce if Plan 01-10 has landed src/welcome/welcome.css.
|
|
if (!existsSync(WELCOME_STYLE_PATH)) {
|
|
// SKIP without failing; documented in plan as conditional artifact.
|
|
return;
|
|
}
|
|
const css = readFileSync(WELCOME_STYLE_PATH, 'utf8');
|
|
const matches = css.match(HEX_LITERAL_REGEX) ?? [];
|
|
expect(
|
|
matches.length,
|
|
matches.length === 0
|
|
? 'unreachable'
|
|
: `Expected 0 hex literals in src/welcome/welcome.css; got ${matches.length}: ${matches.join(', ')}`,
|
|
).toBe(0);
|
|
});
|
|
});
|