Skip to content

Commit 864dba0

Browse files
committed
test(cli): unit tests for the bundle archiver
Covers the cross-path contract: contents at archive root (extracted without stripping), dotfiles and nested .trigger/skills included, node_modules/.DS_Store excluded, dist-like names NOT excluded (the bundle is build output), empty-dir error.
1 parent 4e9f150 commit 864dba0

1 file changed

Lines changed: 88 additions & 0 deletions

File tree

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { mkdtemp, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
2+
import { tmpdir } from "node:os";
3+
import { join } from "node:path";
4+
import * as tar from "tar";
5+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
6+
import { createBundleArchive } from "./bundleArchive.js";
7+
8+
describe("createBundleArchive", () => {
9+
let bundleDir: string;
10+
let outDir: string;
11+
12+
beforeEach(async () => {
13+
bundleDir = await mkdtemp(join(tmpdir(), "bundle-src-"));
14+
outDir = await mkdtemp(join(tmpdir(), "bundle-out-"));
15+
});
16+
17+
afterEach(async () => {
18+
await rm(bundleDir, { recursive: true, force: true });
19+
await rm(outDir, { recursive: true, force: true });
20+
});
21+
22+
it("archives bundle contents at the root, including dotfiles and nested dirs", async () => {
23+
// Shape of a real buildWorker output dir
24+
await writeFile(join(bundleDir, "build.json"), JSON.stringify({ contentHash: "abc" }));
25+
await writeFile(join(bundleDir, "Containerfile"), "FROM scratch");
26+
await writeFile(join(bundleDir, "package.json"), "{}");
27+
await writeFile(join(bundleDir, "index.mjs"), "export {}");
28+
await writeFile(join(bundleDir, ".dockerignore"), "trigger-build-args.json\n");
29+
await writeFile(join(bundleDir, "trigger-build-args.json"), JSON.stringify({ env: {} }));
30+
await mkdir(join(bundleDir, ".trigger", "skills", "my-skill"), { recursive: true });
31+
await writeFile(join(bundleDir, ".trigger", "skills", "my-skill", "SKILL.md"), "# skill");
32+
33+
const archivePath = join(outDir, "bundle.tar.gz");
34+
await createBundleArchive(bundleDir, archivePath);
35+
36+
const extractDir = join(outDir, "extracted");
37+
await mkdir(extractDir);
38+
// The build server extracts WITHOUT stripping path components — the contract
39+
// is that bundle contents live at the archive root.
40+
await tar.extract({ file: archivePath, cwd: extractDir });
41+
42+
const rootEntries = (await readdir(extractDir)).sort();
43+
expect(rootEntries).toEqual(
44+
[
45+
".dockerignore",
46+
".trigger",
47+
"Containerfile",
48+
"build.json",
49+
"index.mjs",
50+
"package.json",
51+
"trigger-build-args.json",
52+
].sort()
53+
);
54+
55+
// Nested dot-dir contents survive
56+
const skill = await readFile(
57+
join(extractDir, ".trigger", "skills", "my-skill", "SKILL.md"),
58+
"utf-8"
59+
);
60+
expect(skill).toBe("# skill");
61+
});
62+
63+
it("excludes node_modules and .DS_Store but nothing else", async () => {
64+
await writeFile(join(bundleDir, "build.json"), "{}");
65+
await writeFile(join(bundleDir, ".DS_Store"), "junk");
66+
await mkdir(join(bundleDir, "node_modules", "leftover"), { recursive: true });
67+
await writeFile(join(bundleDir, "node_modules", "leftover", "index.js"), "x");
68+
// dist-like names must NOT be excluded — the bundle IS build output
69+
await mkdir(join(bundleDir, "dist"), { recursive: true });
70+
await writeFile(join(bundleDir, "dist", "chunk.mjs"), "x");
71+
72+
const archivePath = join(outDir, "bundle.tar.gz");
73+
await createBundleArchive(bundleDir, archivePath);
74+
75+
const extractDir = join(outDir, "extracted");
76+
await mkdir(extractDir);
77+
await tar.extract({ file: archivePath, cwd: extractDir });
78+
79+
const rootEntries = (await readdir(extractDir)).sort();
80+
expect(rootEntries).toEqual(["build.json", "dist"].sort());
81+
});
82+
83+
it("throws when the bundle dir is empty", async () => {
84+
await expect(createBundleArchive(bundleDir, join(outDir, "bundle.tar.gz"))).rejects.toThrow(
85+
/No files found/
86+
);
87+
});
88+
});

0 commit comments

Comments
 (0)