import { expect, test } from "bun:test"; import { readdir, readFile, stat } from "node:fs/promises"; import { join } from "node:path"; import { importPacktVideo } from "../src/jobs/packt-video"; import { makeEnv } from "./harness"; import { makePacktZip, tmp } from "./fixtures"; test("imports a Packt zip into a restricted course with sections, titles and media", async () => { const env = await makeEnv(); const zip = await makePacktZip(await tmp()); const before = await readFile(zip); const r = await importPacktVideo(env.deps, { kind: "packt-video", path: zip, options: { title: "Docker Test" } }, env.jc); expect(r.courseId).toBe("docker-test"); expect(r.warnings).toEqual([]); const c = env.deps.ctx.courses.get("docker-test")!; expect(c.status).toBe("ok"); expect(c.diagnostics).toEqual([]); const m = c.manifest!; expect(m.visibility).toBe("restricted"); expect(m.source?.kind).toBe("packt-video"); expect(m.source?.origin).toBe("video_zip.zip"); expect(m.source?.importedAt).toBeTruthy(); expect(m.modules.map((x) => x.title)).toEqual(["Intro to Docker", "Images (Sample)"]); expect(m.modules.map((x) => x.lessons.map((l) => l.title))).toEqual([["Course Introduction", "Docker & Friends"], ["Topic Introduction - Images"]]); expect(m.modules[0]!.lessons[0]).toMatchObject({ id: "m1-l1", type: "video", file: "media/video1_1.mp4", duration: 2 }); expect(env.deps.ctx.courses.resolvePath("docker-test", "media/video2_1.mp4")).toBeTruthy(); expect(m.cover).toBe("media/cover.jpg"); expect((await readdir(join(env.dataDir, "cache/covers/docker-test"))).sort()).toEqual(["frame-1.jpg", "frame-2.jpg", "frame-3.jpg"]); expect(await readdir(join(env.dataDir, "tmp"))).toEqual([]); // scratch removed expect(Buffer.compare(await readFile(zip), before)).toBe(0); // original untouched expect(env.progress.at(-1)![0]).toBe(1); }); test("second import of the same title gets a fresh id; transcribe requested without a URL warns", async () => { const env = await makeEnv(); const zip = await makePacktZip(await tmp()); await importPacktVideo(env.deps, { path: zip, options: { title: "Same" } }, env.jc); const r = await importPacktVideo(env.deps, { path: zip, options: { title: "Same", transcribe: true } }, env.jc); expect(r.courseId).toBe("same-2"); expect(r.warnings.join()).toContain("STC_TRANSCRIBE_URL is not set"); expect(env.queued).toEqual([]); }); test("a zip that is not a Packt package fails and leaves nothing behind", async () => { const env = await makeEnv(); const d = await tmp(); await Bun.write(join(d, "t", "readme.txt"), "x"); const { zipDir } = await import("./fixtures"); await zipDir(join(d, "t"), join(d, "bad.zip")); await expect(importPacktVideo(env.deps, { path: join(d, "bad.zip") }, env.jc)).rejects.toThrow(/index\.html/); expect(await stat(join(env.dataDir, "courses")).catch(() => null)).toBeNull(); }); test("transcribe option queues the transcription job when a URL is configured", async () => { const env = await makeEnv({ STC_TRANSCRIBE_URL: "http://127.0.0.1:1/v1/audio/transcriptions" }); const zip = await makePacktZip(await tmp()); const r = await importPacktVideo(env.deps, { path: zip, options: { transcribe: true } }, env.jc); expect(env.queued).toEqual([{ kind: "import.transcribe", payload: { courseId: r.courseId } }]); });