import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { describe, expect, it } from 'vitest'; import { APP_ICON_NAMES } from '../../catalog/app-icon-names'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..'); const ICONS_DIR = path.join(ROOT, 'assets', 'icons'); const GENERATED_DIR = path.join(ROOT, 'src', 'renderer', 'ui', 'generated'); describe('AppIcon SVG ↔ catalog 1:1', () => { it('has exactly 80 AppIconName tokens', () => { expect(APP_ICON_NAMES).toHaveLength(80); }); it('has one SVG file per AppIconName and no orphan SVGs', () => { const svgNames = fs .readdirSync(ICONS_DIR) .filter((f) => f.endsWith('.svg')) .map((f) => f.replace(/\.svg$/, '')) .sort(); expect(svgNames).toEqual([...APP_ICON_NAMES].sort()); for (const name of APP_ICON_NAMES) { const text = fs.readFileSync(path.join(ICONS_DIR, `${name}.svg`), 'utf8'); expect(text).toContain('viewBox="0 0 24 24"'); expect(text).toMatch(/currentColor/i); } }); it('has a generated TSX component per AppIconName and registry entries', () => { const generatedTsx = fs .readdirSync(GENERATED_DIR) .filter((f) => f.endsWith('.tsx')) .map((f) => f.replace(/\.tsx$/, '')) .sort(); expect(generatedTsx).toEqual([...APP_ICON_NAMES].sort()); const indexSource = fs.readFileSync(path.join(GENERATED_DIR, 'index.ts'), 'utf8'); expect(indexSource).toContain('GENERATED_ICON_REGISTRY'); for (const name of APP_ICON_NAMES) { expect(indexSource).toContain(`'${name}':`); expect(fs.existsSync(path.join(GENERATED_DIR, `${name}.tsx`))).toBe(true); } }); });