Files
STCourses/packages/feature-import/test/code-repo.test.ts
T
2026-10-30 03:16:00 +01:00

58 lines
3.4 KiB
TypeScript

import { expect, test } from "bun:test";
import { mkdir, readdir, symlink, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { folderName, folderNumber, importCodeRepo } from "../src/jobs/code-repo";
import { importPacktVideo } from "../src/jobs/packt-video";
import { makeEnv } from "./harness";
import { makePacktZip, makeRepoZip, tmp } from "./fixtures";
test("folder names split into number and name", () => {
expect(folderNumber("S08 - Containerizing Applications")).toBe(8);
expect(folderName("S08 - Containerizing Applications")).toBe("Containerizing Applications");
expect(folderNumber("Section 3: Images")).toBe(3);
expect(folderNumber("Bonus Extras")).toBeNull();
});
async function target() {
const env = await makeEnv();
const r = await importPacktVideo(env.deps, { path: await makePacktZip(await tmp()), options: { title: "Docker Test" } }, env.jc);
return { env, id: r.courseId };
}
test("zip repo: folders attach to modules by number, PDFs become deck and attachment", async () => {
const { env, id } = await target();
const zip = await makeRepoZip(await tmp());
const res = await importCodeRepo(env.deps, { kind: "code-repo", path: zip, options: { courseId: id } }, env.jc);
const c = env.deps.ctx.courses.get(id)!;
expect(c.status).toBe("ok");
expect(c.manifest!.modules[0]!.code).toEqual({ dir: "code/S01 - Intro to Docker" });
expect(c.manifest!.modules[1]!.code).toEqual({ dir: "code/S02 - Images (Sample)" });
expect(env.deps.ctx.courses.resolvePath(id, "code/S02 - Images (Sample)/app/main.py")).toBeTruthy();
expect(env.deps.ctx.courses.resolvePath(id, "code/S02 - Images (Sample)/Ünïcode notes.txt")).toBeTruthy();
expect(c.manifest!.decks).toEqual([{ id: "d-slides-intro", file: "media/decks/Slides_Intro.pdf", title: "Slides Intro", attachTo: "m1" }]);
expect(c.manifest!.attachments).toEqual([{ file: "media/files/Docker_CheatSheet.pdf", title: "Docker CheatSheet", module: "m1" }]);
expect(await readdir(join(env.dataDir, "cache/decks", id, "d-slides-intro"))).toContain("p-003.jpg");
expect(await readdir(join(c.root, "code/S01 - Intro to Docker"))).toEqual([]); // PDFs are not duplicated into code
expect(res.warnings).toEqual(['folder "Bonus Extras" matches no module and was skipped']);
});
test("an unnumbered folder matches a module by name; symlinks are not copied; the input is untouched", async () => {
const { env, id } = await target();
const top = join(await tmp(), "repo");
await mkdir(join(top, "Images Sample"), { recursive: true });
await writeFile(join(top, "Images Sample", "a.txt"), "a");
await symlink("/etc/passwd", join(top, "Images Sample", "link"));
const res = await importCodeRepo(env.deps, { path: top, options: { courseId: id } }, env.jc);
expect(res.warnings).toEqual([]);
const c = env.deps.ctx.courses.get(id)!;
expect(c.manifest!.modules[1]!.code).toEqual({ dir: "code/Images Sample" });
expect(await readdir(join(c.root, "code/Images Sample"))).toEqual(["a.txt"]);
expect(await readdir(join(top, "Images Sample"))).toContain("link");
});
test("rejects unmanaged courses and bad git URLs without running git", async () => {
const { env, id } = await target();
await expect(importCodeRepo(env.deps, { path: "/x", options: { courseId: "sample" } }, env.jc)).rejects.toThrow(/only edits courses it created/);
await expect(importCodeRepo(env.deps, { path: "--upload-pack=touch /tmp/pwn", options: { courseId: id } }, env.jc)).rejects.toThrow();
});