Setting the file. One moment. Media Contract Test · Product Launch Video · heygen-com/hyperframes · Skills Docs(opens in a new tab)
scripts/media-contract.test.mjs
JavaScript·200 lines·10 KB
from
"node:child_process"
;
8
9const skillDir = join(dirname(fileURLToPath(import.meta.url)), "..");
10
11test("frame worker documents the approved video-hoist contract", () => {
12 const instructions = readFileSync(join(skillDir, "sub-agents", "frame-worker.md"), "utf8");
13
14 assert.match(instructions, /data-frame-video="approved"/);
15 assert.match(instructions, /assemble-index\.mjs.*hoists it to the host root/i);
16 assert.match(instructions, /Audio remains orchestrator-owned/i);
17});
18
19test("assemble hoists an approved timed frame video to the host root", () => {
20 const project = mkdtempSync(join(tmpdir(), "hf-frame-video-"));
21 mkdirSync(join(project, "compositions"));
22 const framePath = join(project, "compositions", "frame-1.html");
23 writeFileSync(
24 join(project, "STORYBOARD.md"),
25 "---\nformat: 16:9\n---\n\n## Frame 1 — Demo\n- status: built\n- duration: 2s\n- src: compositions/frame-1.html\n",
26 );
27 writeFileSync(
28 framePath,
29 `<html><body><div id="root" data-composition-id="frame-1" data-width="1920" data-height="1080"><video data-frame-video="approved" data-frame-video-x="0" data-frame-video-y="0" data-frame-video-width="1920" data-frame-video-height="1080" src="https://cdn.example/clip.mp4" poster="poster.png" preload="auto" muted playsinline loop style="background:url(https://evil.example/x)" nonce="unsafe" onerror="alert(1)" srcdoc="<script>alert(2)</script>" data-start="0.25" data-duration="1.5" data-media-start="12.75" data-track-index="7"></video></div><script>window.__timelines = {}; window.__timelines["frame-1"] = gsap.timeline();</script></body></html>`,
30 );
31
32 const result = spawnSync(
33 process.execPath,
34 [join(skillDir, "scripts", "assemble-index.mjs"), "--hyperframes", project],
35 { encoding: "utf8" },
36 );
37 assert.equal(result.status, 0, result.stderr);
38 const index = readFileSync(join(project, "index.html"), "utf8");
39 const frame = readFileSync(framePath, "utf8");
40 assert.match(index, /data-start="0\.25"/);
41 assert.match(index, /data-duration="1\.5"/);
42 assert.match(index, /data-media-start="12\.75"/);
43 assert.match(index, /data-track-index="1007"/);
44 assert.match(index, /src="https:\/\/cdn\.example\/clip\.mp4"/);
45 assert.match(index, /poster="poster\.png"/);
46 assert.match(index, /preload="auto"/);
47 assert.match(index, /\smuted(?:\s|>)/);
48 assert.match(index, /\splaysinline(?:\s|>)/);
49 assert.match(index, /\sloop(?:\s|>)/);
50 assert.doesNotMatch(index, /onerror=/i);
51 assert.doesNotMatch(index, /srcdoc=/i);
52 assert.doesNotMatch(index, /nonce=/i);
53 assert.match(
54 index,
55 /style="position:absolute;left:0px;top:0px;width:1920px;height:1080px;object-fit:cover"/,
56 );
57 assert.doesNotMatch(frame, /<video\b/i);
58});
59
60test("assemble preserves approved-video geometry through sanitized host CSS", () => {
61 const project = mkdtempSync(join(tmpdir(), "hf-frame-video-layout-"));
62 mkdirSync(join(project, "compositions"));
63 const framePath = join(project, "compositions", "frame-1.html");
64 writeFileSync(
65 join(project, "STORYBOARD.md"),
66 "---\nformat: 16:9\n---\n\n## Frame 1\n- status: built\n- duration: 2s\n- src: compositions/frame-1.html\n",
67 );
68 writeFileSync(
69 framePath,
70 `<html><body><div id="root" data-composition-id="frame-1" data-width="1920" data-height="1080"><video class="clip approved-demo" data-frame-video="approved" data-frame-video-x="120" data-frame-video-y="240" data-frame-video-width="960" data-frame-video-height="540" data-frame-video-fit="cover" src="clip.mp4" style="position:fixed;background:url(https://evil.example/x)" nonce="unsafe" onerror="alert(1)" srcdoc="<script>alert(2)</script>" data-start="0" data-duration="1" data-track-index="7"></video></div><script>window.__timelines = {}; window.__timelines["frame-1"] = gsap.timeline();</script></body></html>`,
71 );
72
73 const result = spawnSync(
74 process.execPath,
75 [join(skillDir, "scripts", "assemble-index.mjs"), "--hyperframes", project],
76 { encoding: "utf8" },
77 );
78
79 assert.equal(result.status, 0, result.stderr);
80 const index = readFileSync(join(project, "index.html"), "utf8");
81 assert.match(
82 index,
83 /style="position:absolute;left:120px;top:240px;width:960px;height:540px;object-fit:cover"/,
84 );
85 assert.doesNotMatch(index, /approved-demo/);
86 assert.doesNotMatch(index, /evil\.example/);
87 assert.doesNotMatch(index, /position:fixed/);
88 assert.doesNotMatch(index, /data-frame-video-(?:x|y|width|height|fit)=/);
89 assert.doesNotMatch(index, /onerror=|srcdoc=|nonce=/i);
90 assert.doesNotMatch(readFileSync(framePath, "utf8"), /<video\b/i);
91});
92
93test("rejects partial or unsafe approved-video layout geometry", () => {
94 const project = mkdtempSync(join(tmpdir(), "hf-frame-video-layout-invalid-"));
95 mkdirSync(join(project, "compositions"));
96 writeFileSync(
97 join(project, "STORYBOARD.md"),
98 "---\nformat: 16:9\n---\n\n## Frame 1\n- status: built\n- duration: 2s\n- src: compositions/frame-1.html\n",
99 );
100 writeFileSync(
101 join(project, "compositions", "frame-1.html"),
102 `<html><body><div id="root" data-composition-id="frame-1" data-width="1920" data-height="1080"><video data-frame-video="approved" data-frame-video-x="0" data-frame-video-y="0" data-frame-video-width="calc(100% + 1px)" data-frame-video-height="1080" data-frame-video-fit="cover" src="clip.mp4" data-start="0" data-duration="1" data-track-index="0"></video></div><script>window.__timelines = {}; window.__timelines["frame-1"] = gsap.timeline();</script></body></html>`,
103 );
104
105 const result = spawnSync(
106 process.execPath,
107 [join(skillDir, "scripts", "assemble-index.mjs"), "--hyperframes", project],
108 { encoding: "utf8" },
109 );
110
111 assert.notEqual(result.status, 0);
112 assert.match(result.stderr, /approved frame video layout.*finite numeric/i);
113 assert.equal(existsSync(join(project, "index.html")), false);
114});
115
116test("rejects an approved video without mandatory layout geometry", () => {
117 const project = mkdtempSync(join(tmpdir(), "hf-frame-video-layout-missing-"));
118 mkdirSync(join(project, "compositions"));
119 writeFileSync(
120 join(project, "STORYBOARD.md"),
121 "---\nformat: 16:9\n---\n\n## Frame 1\n- status: built\n- duration: 2s\n- src: compositions/frame-1.html\n",
122 );
123 writeFileSync(
124 join(project, "compositions", "frame-1.html"),
125 `<html><body><div id="root" data-composition-id="frame-1" data-width="1920" data-height="1080"><video data-frame-video="approved" src="clip.mp4" data-start="0" data-duration="1" data-track-index="0"></video></div><script>window.__timelines = {}; window.__timelines["frame-1"] = gsap.timeline();</script></body></html>`,
126 );
127
128 const result = spawnSync(
129 process.execPath,
130 [join(skillDir, "scripts", "assemble-index.mjs"), "--hyperframes", project],
131 { encoding: "utf8" },
132 );
133
134 assert.notEqual(result.status, 0);
135 assert.match(result.stderr, /approved frame video layout.*finite numeric/i);
136 assert.equal(existsSync(join(project, "index.html")), false);
137});
138
139test("rejects empty approved-video layout coordinates", () => {
140 const project = mkdtempSync(join(tmpdir(), "hf-frame-video-layout-empty-"));
141 mkdirSync(join(project, "compositions"));
142 writeFileSync(
143 join(project, "STORYBOARD.md"),
144 "---\nformat: 16:9\n---\n\n## Frame 1\n- status: built\n- duration: 2s\n- src: compositions/frame-1.html\n",
145 );
146 writeFileSync(
147 join(project, "compositions", "frame-1.html"),
148 `<html><body><div id="root" data-composition-id="frame-1" data-width="1920" data-height="1080"><video data-frame-video="approved" data-frame-video-x="" data-frame-video-y="0" data-frame-video-width="1920" data-frame-video-height="1080" src="clip.mp4" data-start="0" data-duration="1" data-track-index="0"></video></div><script>window.__timelines = {}; window.__timelines["frame-1"] = gsap.timeline();</script></body></html>`,
149 );
150
151 const result = spawnSync(
152 process.execPath,
153 [join(skillDir, "scripts", "assemble-index.mjs"), "--hyperframes", project],
154 { encoding: "utf8" },
155 );
156
157 assert.notEqual(result.status, 0);
158 assert.match(result.stderr, /approved frame video layout.*finite numeric/i);
159 assert.equal(existsSync(join(project, "index.html")), false);
160});
161
162test("rejects an approved video with missing admission timing", () => {
163 const project = mkdtempSync(join(tmpdir(), "hf-frame-video-missing-"));
164 mkdirSync(join(project, "compositions"));
165 writeFileSync(
166 join(project, "STORYBOARD.md"),
167 "---\nformat: 16:9\n---\n\n## Frame 1\n- status: built\n- duration: 2s\n- src: compositions/frame-1.html\n",
168 );
169 writeFileSync(
170 join(project, "compositions", "frame-1.html"),
171 `<html><body><div id="root" data-composition-id="frame-1" data-width="1920" data-height="1080"><video data-frame-video="approved" src="clip.mp4" data-duration="1" data-track-index="0"></video></div><script>window.__timelines = {}; window.__timelines["frame-1"] = gsap.timeline();</script></body></html>`,
172 );
173 const result = spawnSync(
174 process.execPath,
175 [join(skillDir, "scripts", "assemble-index.mjs"), "--hyperframes", project],
176 { encoding: "utf8" },
177 );
178 assert.notEqual(result.status, 0);
179 assert.match(result.stderr, /must declare quoted data-start/i);
180});
181
182test("does not hoist declarations hidden in comments or scripts", () => {
183 const project = mkdtempSync(join(tmpdir(), "hf-frame-video-hidden-"));
184 mkdirSync(join(project, "compositions"));
185 writeFileSync(
186 join(project, "STORYBOARD.md"),
187 "---\nformat: 16:9\n---\n\n## Frame 1\n- status: built\n- duration: 2s\n- src: compositions/frame-1.html\n",
188 );
189 writeFileSync(
190 join(project, "compositions", "frame-1.html"),
191 `<html><body><div id="root" data-composition-id="frame-1" data-width="1920" data-height="1080"></div><script>window.__timelines = {}; window.__timelines["frame-1"] = gsap.timeline(); const s = '<video data-frame-video="approved" data-start="0" data-duration="1" data-track-index="1"></video>';</script><!-- <video data-frame-video="approved" data-start="0" data-duration="1" data-track-index="2"></video> --></body></html>`,
192 );
193 const result = spawnSync(
194 process.execPath,
195 [join(skillDir, "scripts", "assemble-index.mjs"), "--hyperframes", project],
196 { encoding: "utf8" },
197 );
198 assert.equal(result.status, 0, result.stderr);
199 assert.doesNotMatch(readFileSync(join(project, "index.html"), "utf8"), /data-track-index="1001"/);
200});