Setting the file. One moment. Make Theme Test · Embedded Captions · heygen-com/hyperframes · Skills Docs14.42
Hershey Script1
(opens in a new tab)
scripts/make-theme.test.mjs
JavaScript·131 lines·5 KB
{ tmpdir }
from
"node:os"
;
13import { dirname, join, resolve } from "node:path";
14import test from "node:test";
15import { fileURLToPath } from "node:url";
16
17const scriptsDir = dirname(fileURLToPath(import.meta.url));
18const skillDir = resolve(scriptsDir, "..");
19const fixturesDir = join(scriptsDir, "fixtures", "heroless");
20const makeTheme = join(scriptsDir, "make-theme.cjs");
21const themeNames = readdirSync(join(skillDir, "themes"))
22 .filter((name) => name.endsWith(".json"))
23 .map((name) => name.slice(0, -5))
24 .sort();
25const expectedThemes = [
26 "anchor",
27 "arcade",
28 "aurora",
29 "biolume",
30 "brush",
31 "chalkboard",
32 "dossier",
33 "graffiti",
34 "hologram",
35 "inkwater",
36 "laser",
37 "lastpage",
38 "neonsign",
39 "ordnance",
40 "papercut",
41 "popup",
42 "ransom",
43 "scoreboard",
44 "spectrum",
45 "stardust",
46 "stomp",
47 "terminal",
48 "thunder",
49 "transit",
50 "vhs",
51];
52const fixtureTheme = JSON.parse(readFileSync(join(fixturesDir, "theme.json"), "utf8"));
53const fixtureWords = fixtureTheme.lines.flat();
54
55test("every embedded-caption theme compiles a sane heroless body timeline", async (t) => {
56 assert.deepEqual(themeNames, expectedThemes);
57 assert.equal(Object.hasOwn(fixtureTheme, "hero"), false);
58
59 const workspace = mkdtempSync(join(tmpdir(), "embedded-captions-heroless-"));
60 t.after(() => rmSync(workspace, { recursive: true, force: true }));
61
62 for (const themeName of themeNames) {
63 await t.test(themeName, () => {
64 const project = join(workspace, themeName);
65 cpSync(fixturesDir, project, { recursive: true });
66 writeFileSync(
67 join(project, "theme.json"),
68 JSON.stringify({ ...fixtureTheme, dna: themeName }),
69 );
70
71 const result = spawnSync(process.execPath, [makeTheme, project], {
72 encoding: "utf8",
73 timeout: 10_000,
74 });
75 assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`);
76
77 const dna = JSON.parse(readFileSync(join(skillDir, "themes", `${themeName}.json`), "utf8"));
78 const bodyPage = dna.body.layer === "bg" ? "index.html" : "rail.html";
79 const generated = readFileSync(join(project, bodyPage), "utf8");
80 const generatedPages = readdirSync(project)
81 .filter((name) => name.endsWith(".html"))
82 .map((name) => readFileSync(join(project, name), "utf8"));
83
84 assert.match(generated, /data-composition-id="main"[^>]+data-duration="6"/s);
85 assert.match(generated, /window\.__timelines\["main"\] = tl;/);
86 for (const word of fixtureWords) assert.match(generated, new RegExp(`\\b${word}\\b`, "i"));
87 for (const page of generatedPages) assert.doesNotMatch(page, /-99\d(?:\.\d+)?/);
88 });
89 }
90});
91
92for (const heroless of [false, true]) {
93 for (const grain of [0, 3, undefined]) {
94 test(`postfx preserves grain ${grain} with heroless=${heroless}`, (t) => {
95 const workspace = mkdtempSync(join(tmpdir(), "embedded-captions-grain-"));
96 t.after(() => rmSync(workspace, { recursive: true, force: true }));
97 const project = join(workspace, "project");
98 cpSync(fixturesDir, project, { recursive: true });
99 mkdirSync(join(workspace, "scripts"));
100 mkdirSync(join(workspace, "themes"));
101 const compiler = join(workspace, "scripts", "make-theme.cjs");
102 cpSync(makeTheme, compiler);
103 const dna = JSON.parse(readFileSync(join(skillDir, "themes", "anchor.json"), "utf8"));
104 dna.plate.grain = grain;
105 writeFileSync(join(workspace, "themes", "anchor.json"), JSON.stringify(dna));
106 writeFileSync(
107 join(project, "theme.json"),
108 JSON.stringify({
109 ...fixtureTheme,
110 dna: "anchor",
111 ...(heroless
112 ? {}
113 : {
114 hero: { match: "hero" },
115 lines: fixtureTheme.lines.map((line) => line.filter((word) => word !== "hero")),
116 }),
117 }),
118 );
119 const result = spawnSync(process.execPath, [compiler, project], {
120 encoding: "utf8",
121 timeout: 10_000,
122 });
123 assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`);
124 const postfx = readFileSync(join(project, "_postfx.sh"), "utf8");
125 if (grain === 0) assert.doesNotMatch(postfx, /noise=/);
126 else assert.match(postfx, new RegExp(`noise=alls=${grain ?? 5}:allf=t\\+u`));
127 assert.doesNotMatch(postfx, /,\s*\[v\]/);
128 assert.match(postfx, heroless ? /\[0:v\]null/ : /zoompan=/);
129 });
130 }
131}