import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import test from "node:test";
const workflowScripts = [
["product-launch-video", new URL("./transitions.mjs", import.meta.url).pathname],
["pr-to-video", new URL("../../pr-to-video/scripts/transitions.mjs", import.meta.url).pathname],
];
function runInject(script, rootId) {
const project = mkdtempSync(join(tmpdir(), "hf-transition-root-"));
const framesDir = join(project, "compositions", "frames");
mkdirSync(framesDir, { recursive: true });
writeFileSync(
join(project, "STORYBOARD.md"),
`---\nformat: 1920x1080\n---\n\n## Frame 1 — First\n\n- duration: 3s\n- transition_in: cut\n- src: compositions/frames/frame-01.html\n\n## Frame 2 — Second\n\n- duration: 3s\n- transition_in: crossfade 0.5s\n- src: compositions/frames/frame-02.html\n`,
);
writeFileSync(
join(framesDir, "frame-01.html"),
`
`,
);
writeFileSync(
join(framesDir, "frame-02.html"),
'',
);
writeFileSync(
join(project, "index.html"),
``,
);
const result = spawnSync(
process.execPath,
[script, "inject", "--storyboard", join(project, "STORYBOARD.md"), "--hyperframes", project],
{ encoding: "utf8" },
);
return {
project,
result,
frameHtml: () => readFileSync(join(framesDir, "frame-01.html"), "utf8"),
};
}
for (const [workflow, script] of workflowScripts) {
test(`${workflow} inserts duration on a valid durationless frame root`, () => {
const fixture = runInject(script, "frame-01");
try {
assert.equal(fixture.result.status, 0, fixture.result.stderr);
assert.match(fixture.frameHtml(), /data-composition-id="frame-01"[^>]*data-duration="3\.5"/);
} finally {
rmSync(fixture.project, { recursive: true, force: true });
}
});
test(`${workflow} still rejects a genuinely mismatched frame root`, () => {
const fixture = runInject(script, "wrong-root");
try {
assert.notEqual(fixture.result.status, 0);
assert.match(fixture.result.stderr, /has no data-composition-id="frame-01" root/);
} finally {
rmSync(fixture.project, { recursive: true, force: true });
}
});
}