import { readFileSync } from "node:fs"; import assert from "node:assert/strict"; import test from "node:test"; /** * BUG-737: `--font-display` led with "Tiempos Headline" and `--font-body` with * StyreneB. Both are Anthropic licensed faces this app has never loaded — no * @font-face, nothing in public/, and layout.tsx vendors only Inter — so every * CJK heading fell through to the next entry, Songti SC / SimSun, for the life * of the product. Nothing failed, because nothing checked that a declared family * can actually resolve. * * This contract closes that: every quoted family in the two stacks must either * be vendored through next/font/local, or be a face the OS is known to ship. */ const css = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8"); const layout = readFileSync(new URL("../src/app/layout.tsx", import.meta.url), "utf8"); /** Faces that ship with a target OS, so naming them costs no request. */ const SYSTEM_FACES = new Set([ // Apple "PingFang SC", "Helvetica Neue", // Windows "Microsoft YaHei", "Segoe UI", // Cross-platform fallbacks that are generic families or UA keywords. "Georgia", "Consolas", "SFMono-Regular", "JetBrains Mono", ]); function stackValue(token: string): string { const match = css.match(new RegExp(`^\\s*${token}:\\s*([^;]+);`, "m")); assert.ok(match, `${token} must be declared in globals.css`); return match![1]; } function quotedFamilies(stack: string): string[] { return [...stack.matchAll(/"([^"]+)"/g)].map((m) => m[1]); } /** Families vendored via next/font/local, keyed by the CSS variable they expose. */ function vendoredVariables(): string[] { return [...layout.matchAll(/variable:\s*"(--[a-z0-9-]+)"/g)].map((m) => m[1]); } test("every quoted family in the UI font stacks is either vendored or a system face", () => { for (const token of ["--font-display", "--font-body"]) { const stack = stackValue(token); for (const family of quotedFamilies(stack)) { assert.ok( SYSTEM_FACES.has(family), `${token} names "${family}", which is neither vendored via next/font/local nor a known system face. ` + "A family that cannot load is dead configuration: it makes the stack look intentional while the " + "browser silently falls through to the next entry. Vendor it into src/app/fonts/ with an OFL/SIL " + "licence file beside it, or drop the name. See BUG-737.", ); } } }); test("the UI font stacks resolve through the vendored Inter variable", () => { const vendored = vendoredVariables(); assert.ok(vendored.includes("--font-inter"), "layout.tsx must vendor Inter through next/font/local"); for (const token of ["--font-display", "--font-body"]) { assert.match( stackValue(token), /var\(--font-inter, Inter\)/, `${token} must route through the vendored Inter variable rather than naming a face it cannot load`, ); } }); test("no CJK serif is reachable from the display stack", () => { // The fix is not "pick a different serif" — it is that Chinese text never // takes a serif here. A Latin-serif-first stack was measured and rejected: // Newsreader's latin subset costs 132 KB to serif one wordmark, and it splits // a mixed heading such as "D10 事业盘怎么读" into two scripts. const display = stackValue("--font-display"); for (const banned of ["Songti", "STSong", "SimSun", "Noto Serif", "Source Han Serif"]) { assert.doesNotMatch( display, new RegExp(banned.replace(/ /g, "\\s")), `--font-display must not reach "${banned}"; CJK headings rendered in 宋体 is exactly BUG-737`, ); } // The generic `serif` keyword too — but not the `sans-serif` it is a suffix of. assert.doesNotMatch( display, /(^|[\s,])serif\b/, "--font-display must not end in the generic serif family; the UA default for CJK there is 宋体", ); }); test("display rank comes from weight, not from a second family", () => { // With one shared stack, every rule that reaches for --font-display has to // carry its own weight, or it renders at body rank and the hierarchy is gone. const displayRules = [...css.matchAll(/font-family:\s*var\(--font-display\)/g)]; assert.ok(displayRules.length > 10, "sanity: the display token should still be in wide use"); assert.doesNotMatch( css, /font-family:\s*var\(--font-display\);\s*font-size:[^;]*;\s*font-weight:\s*400\s*;/, "a --font-display rule still sits at weight 400; with a sans stack that is body rank", ); });