// tests/build/fonts-present.test.ts — Plan 01-12 Wave 0 RED unit test. // // Asserts that the self-hosted WOFF2 font bundle lives at src/shared/fonts/ // per D-05 typography pairing + R2 Lora substitution (designer reply // 2026-05-19; Newsreader → Lora for Cyrillic coverage). // // Polarity at Wave 0 land: RED across the board (src/shared/fonts/ does // not exist). Flips GREEN after Wave 1 Task 1 lands the WOFF2 bundle. // // NOTE on Lora italic: per RESEARCH §A5, if upstream Lora variable file // ships italic via the `ital` axis (single multi-axis file), the // `Lora-Italic-VariableFont.woff2` file is omitted and the @font-face // rule in tokens.css uses `font-style: oblique 0deg 14deg`. This test // permits both layouts via the OPTIONAL_FILES set. import { describe, expect, it } from 'vitest'; import { existsSync, readFileSync, statSync } from 'node:fs'; import { resolve as resolvePath } from 'node:path'; const FONTS_DIR = resolvePath(process.cwd(), 'src/shared/fonts'); const TOKENS_CSS_PATH = resolvePath(process.cwd(), 'src/shared/tokens.css'); /** Required WOFF2 faces — Plex Sans + Plex Mono fixed weights + Lora normal */ const REQUIRED_FONT_FILES: ReadonlyArray = [ 'Lora-VariableFont.woff2', 'IBMPlexSans-Regular.woff2', 'IBMPlexSans-Medium.woff2', 'IBMPlexSans-SemiBold.woff2', 'IBMPlexSans-Bold.woff2', 'IBMPlexMono-Regular.woff2', 'IBMPlexMono-Medium.woff2', ]; /** Optional faces — A5 verify: present iff upstream ships separate italic file */ const OPTIONAL_FONT_FILES: ReadonlyArray = [ 'Lora-Italic-VariableFont.woff2', ]; /** Companion artifacts (LICENSE + README) */ const REQUIRED_LICENSE_FILES: ReadonlyArray = [ 'LICENSE-Lora.txt', 'LICENSE-IBM-Plex.txt', 'README.md', ]; /** WOFF2 magic bytes (RFC 8081): 'wOF2' */ const WOFF2_SIGNATURE = Buffer.from([0x77, 0x4f, 0x46, 0x32]); describe('Plan 01-12: self-hosted OFL font bundle (Lora + Plex Sans + Plex Mono)', () => { describe('required WOFF2 faces', () => { for (const name of REQUIRED_FONT_FILES) { it(`src/shared/fonts/${name} exists + non-empty + WOFF2 signature`, () => { const filePath = resolvePath(FONTS_DIR, name); expect(existsSync(filePath), `Expected ${filePath} (RED until Wave 1 Task 1)`).toBe(true); const size = statSync(filePath).size; expect(size, `${name} must be non-empty`).toBeGreaterThan(0); const head = Buffer.alloc(4); const fd = require('node:fs').openSync(filePath, 'r'); try { require('node:fs').readSync(fd, head, 0, 4, 0); } finally { require('node:fs').closeSync(fd); } expect( head.equals(WOFF2_SIGNATURE), `${name} signature must be 'wOF2' (0x77 0x4F 0x46 0x32); got ${head.toString('hex')}`, ).toBe(true); }); } }); it('tokens.css references every required WOFF2 file by filename', () => { if (!existsSync(TOKENS_CSS_PATH)) { // Will be RED until Wave 1 Task 2 lands tokens.css. Surface a clear diagnostic // rather than letting downstream substring assertions fail with confusing output. throw new Error(`src/shared/tokens.css missing — Wave 1 Task 2 lands this file`); } const css = readFileSync(TOKENS_CSS_PATH, 'utf8'); for (const name of REQUIRED_FONT_FILES) { expect( css.includes(name), `tokens.css must reference ${name} in a @font-face src url(); RED until Wave 1 Task 2 lands the @font-face block`, ).toBe(true); } }); it('LICENSE-Lora.txt + LICENSE-IBM-Plex.txt + README.md exist (OFL attribution)', () => { for (const name of REQUIRED_LICENSE_FILES) { const filePath = resolvePath(FONTS_DIR, name); expect(existsSync(filePath), `Expected ${filePath} (RED until Wave 1 Task 1)`).toBe(true); expect(statSync(filePath).size, `${name} must be non-empty`).toBeGreaterThan(0); } }); it('optional Lora-Italic-VariableFont.woff2 — present iff upstream ships separate italic file', () => { // A5 in RESEARCH Assumptions Log: variable Lora may consolidate italic // via the `ital` axis. This test is informational — passes either way. for (const name of OPTIONAL_FONT_FILES) { const filePath = resolvePath(FONTS_DIR, name); if (existsSync(filePath)) { expect(statSync(filePath).size).toBeGreaterThan(0); } // If absent, the README.md should document the consolidation (verified // empirically at execute time; not asserted here to avoid coupling). } }); });