// Run with: node_modules/.bin/tsx --test "app/**/*.test.ts" (from editor/). // // VideoPanel's JSX is literal; this pins that the chore cards it renders, in // the order it renders them, are exactly VIDEO_CHORE_CARDS. Read as source text // rather than imported: the cards are client components (StreamActionLog, // next/link, server-action references) and a node test cannot load them. import { test } from "node:test"; import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const here = path.dirname(fileURLToPath(import.meta.url)); const listSrc = readFileSync(path.join(here, "videoChoreCards.ts"), "utf8"); const panelSrc = readFileSync( path.join(here, "../components/VideoPanel.tsx"), "utf8", ); const listed = [...listSrc.matchAll(/^\s+component: (\w+),$/gm)].map((m) => m[1]); test("the hand-list names fifteen distinct chore cards", () => { assert.equal(listed.length, 15); assert.equal(new Set(listed).size, listed.length); }); test("VideoPanel renders exactly the listed cards, in list order", () => { const known = new Set(listed); const rendered = [...panelSrc.matchAll(/<(\w+)\b/g)] .map((m) => m[1]) .filter((name) => known.has(name)); assert.deepEqual(rendered, listed); }); // What lives in ./cards but is not a chore: the transcript reader with its // track switcher (multi-track captions) is read, never run. const NOT_CHORES = new Set(["TranscriptTracksReader"]); test("every card VideoPanel imports from ./cards is listed", () => { const imported = [ ...panelSrc.matchAll(/^import \{ (\w+)(?:, type \w+)? \} from "\.\/cards\/\w+";$/gm), ] .map((m) => m[1]) .filter((name) => !NOT_CHORES.has(name)); assert.deepEqual([...imported].sort(), [...listed].sort()); });