import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { test } from "node:test"; import ts from "typescript"; import { parseHTML } from "linkedom"; const source = readFileSync(new URL("../src/player/cutscene.ts", import.meta.url), "utf8"); const { outputText } = ts.transpileModule(source, { compilerOptions: { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.ESNext } }); const { cutscene } = await import(`data:text/javascript;base64,${Buffer.from(outputText).toString("base64")}`); function setup(options = {}, blocked = false) { const { document } = parseHTML(""); globalThis.document = document; const create = document.createElement.bind(document); let starts = 0; document.createElement = (name) => { const element = create(name); if (name === "video") { element.play = () => { starts++; return blocked ? Promise.reject(new Error("gesture")) : Promise.resolve(); }; element.pause = () => {}; } return element; }; const movie = cutscene(document.body, "/film.webm", { delay: null, loops: 0, volume: 0.5, ...options }); return { ...movie, document, video: document.querySelector("video"), starts: () => starts }; } test("a cutscene waits for its final loop and returns false on natural completion", async () => { const movie = setup({ loops: 1 }); movie.video.onended(); assert.equal(movie.starts(), 2); movie.video.onended(); assert.equal(await movie.finished, false); movie.destroy(); assert.equal(movie.document.querySelector("video"), null); }); test("clicking skips a cutscene and delay -1 holds its last frame", async () => { const movie = setup({ delay: -1 }); movie.video.onended(); let resolved = false; movie.finished.then(() => { resolved = true; }); await Promise.resolve(); assert.equal(resolved, false); movie.document.querySelector(".pg-cutscene").onclick({ stopPropagation() {} }); assert.equal(await movie.finished, true); movie.destroy(); }); test("a timed cutscene completes after playback starts", async () => { const movie = setup({ delay: 0 }); movie.video.onplaying(); assert.equal(await movie.finished, false); movie.destroy(); }); test("blocked autoplay offers a play button, and media errors fail explicitly", async () => { const movie = setup({}, true); await Promise.resolve(); assert.equal(movie.document.querySelector("button").hidden, false); const failed = assert.rejects(movie.finished, /Не удалось воспроизвести/); movie.video.onerror(); await failed; movie.destroy(); });