// Tests for the opt-in brand preset (brand.mjs) and the hooks it has in the // build: the config it resolves, and -- the hard rule -- that a manifest // WITHOUT `render.brand` comes through every hook exactly as it went in. // // The pixels themselves are proven by rendering (a guarded test below, and the // before/after card diff recorded in plans/brand-and-themes.md). // // Run with: pnpm test:scripts import assert from "node:assert/strict"; import test from "node:test"; import { execFileSync, spawnSync } from "node:child_process"; import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { mkdir } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; import { BRAND_IDS, END_CARD_DEFAULT_SECONDS, END_CARD_DEFAULT_URL, END_CARD_ID, FACES, FONTCONFIG_FILE, FONTS_DIR, MONO_BOLD_FONT_FILE, MONO_FONT_FILE, brandFaces, brandHeaderGeometry, brandKit, brandManifest, brandSvgFace, childOpts, endCardConfig, resolveBrandRender, } from "./brand.mjs"; import { headerFilters, selectVariant } from "./build-video.mjs"; import { renderCard, renderScrollCard } from "./render-cards.mjs"; import { markPng, renderThumbnail, THUMB } from "./brand-cards.mjs"; import { IBM_PLEX_SANS } from "./svg-faces.mjs"; const mkdirP = (d) => mkdir(d, { recursive: true }); const HERE = path.dirname(fileURLToPath(import.meta.url)); const PLAIN_RENDER = { width: 1920, height: 1080, fps: 30, headerHeight: 56, fontRegular: "/usr/share/fonts/TTF/FiraSans-Regular.ttf", palette: { bg: "#12100c", fg: "#f6f1e6", muted: "#a2957f", accent: "#c8752a", amber: "#ffc860" }, }; const manifest = (render, timeline = [{ type: "clip", id: "c01" }]) => ({ slug: "t", render, timeline, provenance: {}, }); test("no brand: every hook hands back the very object it was given", () => { assert.equal(resolveBrandRender(PLAIN_RENDER), PLAIN_RENDER); const m = manifest(PLAIN_RENDER); assert.equal(brandManifest(m), m); assert.equal(brandFaces(PLAIN_RENDER), null); assert.equal(brandSvgFace(PLAIN_RENDER), null); const opts = { maxBuffer: 1 }; assert.equal(childOpts(PLAIN_RENDER, opts), opts); assert.equal(childOpts(PLAIN_RENDER, undefined), undefined); }); test("no brand: selectVariant's result is the pre-preset shape, render untouched, no end card", () => { const m = manifest(PLAIN_RENDER, [ { type: "card", id: "t00", style: "title" }, { type: "clip", id: "c01" }, { type: "card", id: "L1", variant: "full" }, ]); const v = selectVariant(m, "sourced"); assert.equal(v.render, PLAIN_RENDER); assert.deepEqual(v, { ...m, variant: "sourced", timeline: m.timeline.slice(0, 2), ledger: [] }); }); test("no brand: the header is the accent tick and one drawtext line, as it always was", () => { assert.deepEqual(headerFilters(PLAIN_RENDER, "/o/c01.attrib.txt", "/o/c01.channel.txt"), [ "drawbox=x=90:y=16:w=4:h=24:color=#c8752a:t=fill", "drawtext=textfile='/o/c01.attrib.txt':fontfile='/usr/share/fonts/TTF/FiraSans-Regular.ttf'" + ":fontsize=22:fontcolor=#a2957f:x=118:y=15", ]); }); test("the preset owns palette and face, and resolves the end card", () => { const r = resolveBrandRender({ ...PLAIN_RENDER, brand: "archilyzer-media" }); assert.deepEqual(r.palette, { bg: "#151b20", fg: "#e7edf1", muted: "#8496a2", accent: "#5fa8a0", amber: "#e3b15c", dim: "#586977", }); assert.equal(r.fontRegular, MONO_FONT_FILE); // The HyperFrames band's bold: the vendored Plex Mono Bold, whatever the manifest said. assert.equal(r.fontBold, MONO_BOLD_FONT_FILE); assert.equal( resolveBrandRender({ ...PLAIN_RENDER, fontBold: "/usr/share/fonts/TTF/FiraSans-Bold.ttf", brand: "archilyzer-media" }).fontBold, MONO_BOLD_FONT_FILE, ); // The rail / ledger / scroll / chart text: Plex Sans, measured per character. assert.equal(brandSvgFace(r), IBM_PLEX_SANS); assert.deepEqual(r.endCard, { seconds: END_CARD_DEFAULT_SECONDS, url: END_CARD_DEFAULT_URL }); // Everything else is still the manifest's. assert.equal(r.headerHeight, 56); assert.equal(r.fps, 30); assert.throws(() => resolveBrandRender({ ...PLAIN_RENDER, brand: "acme" }), /not a preset/); assert.deepEqual(BRAND_IDS, ["archilyzer-media"]); }); test("endCardConfig: default 20 s, a number, an object, or false", () => { assert.deepEqual(endCardConfig(undefined), { seconds: 20, url: "archilyzer.pages.dev" }); assert.deepEqual(endCardConfig(12), { seconds: 12, url: "archilyzer.pages.dev" }); assert.deepEqual(endCardConfig({ seconds: 8, url: "example.org" }), { seconds: 8, url: "example.org" }); assert.equal(endCardConfig(false), null); assert.throws(() => endCardConfig({ seconds: 0 }), /positive/); }); test("endCard false stays off when a render block is resolved twice", () => { assert.equal(endCardConfig(null), null); const branded = { ...PLAIN_RENDER, brand: "archilyzer-media" }; const once = resolveBrandRender({ ...branded, endCard: false }); assert.equal(once.endCard, null); const twice = resolveBrandRender(once); assert.equal(twice.endCard, null); assert.equal(brandManifest(manifest(twice)).timeline.length, 1); // A configured card resolves to itself. const on = resolveBrandRender({ ...branded, endCard: { seconds: 12 } }); assert.deepEqual(resolveBrandRender(on).endCard, on.endCard); }); test("brandManifest appends one end card, clear of the rail, unless told otherwise", () => { const branded = { ...PLAIN_RENDER, brand: "archilyzer-media" }; const m = brandManifest(manifest(branded)); assert.deepEqual(m.timeline.at(-1), { type: "card", id: END_CARD_ID, style: "end", seconds: 20, hideRail: true, chapter: "End", }); assert.equal(m.timeline.length, 2); // Configured length. assert.equal(brandManifest(manifest({ ...branded, endCard: { seconds: 15 } })).timeline.at(-1).seconds, 15); // Off. assert.equal(brandManifest(manifest({ ...branded, endCard: false })).timeline.length, 1); // The author's own end card is not doubled. const own = [{ type: "clip", id: "c01" }, { type: "card", id: "bye", style: "end", seconds: 10 }]; assert.deepEqual(brandManifest(manifest(branded, own)).timeline, own); // An unrelated entry called "end" is a collision, said rather than overwritten. assert.throws(() => brandManifest(manifest(branded, [{ type: "clip", id: "end" }])), /already has an entry/); // Through selectVariant, which every reader of a cut uses. assert.equal(selectVariant(manifest(branded), "full").timeline.at(-1).style, "end"); }); test("branded header: mono face, no tick, the channel drawn again in the foreground", () => { const r = resolveBrandRender({ ...PLAIN_RENDER, brand: "archilyzer-media" }); const g = brandHeaderGeometry(r); assert.deepEqual(g, { mark: 34, markX: 90, markY: 11, textX: 138, fontSize: 20, textY: 20 }); const f = headerFilters(r, "/o/a.txt", "/o/c.txt"); assert.equal(f.length, 2); assert.ok(f.every((s) => s.startsWith("drawtext="))); assert.match(f[0], /textfile='\/o\/a\.txt'.*fontcolor=#8496a2:x=138:y=20$/); assert.match(f[1], /textfile='\/o\/c\.txt'.*fontcolor=#e7edf1:x=138:y=20$/); assert.ok(f[0].includes(`fontfile='${MONO_FONT_FILE}'`)); assert.equal(headerFilters(r, "/o/a.txt").length, 1); }); test("the vendored faces: every file the preset names is there, under the OFL", () => { for (const f of [ "Archivo[wdth,wght].ttf", "IBMPlexSans[wdth,wght].ttf", "IBMPlexMono-Regular.ttf", "IBMPlexMono-Bold.ttf", "OFL.txt", "fonts.conf", ]) { assert.ok(existsSync(path.join(FONTS_DIR, f)), f); } assert.ok(existsSync(MONO_BOLD_FONT_FILE)); assert.equal(FONTCONFIG_FILE, path.join(FONTS_DIR, "fonts.conf")); const ofl = readFileSync(path.join(FONTS_DIR, "OFL.txt"), "utf8"); assert.match(ofl, /The Archivo Project Authors/); assert.match(ofl, /IBM Corp\. with Reserved Font Name "Plex"/); assert.match(readFileSync(FONTCONFIG_FILE, "utf8"), /