Files
kuber/tests/lib/yaml.test.ts
T
2026-10-06 15:31:51 +00:00

108 lines
3.8 KiB
TypeScript

import { afterEach, describe, expect, test } from "bun:test";
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { readCompose, resolveComposeFile } from "../../lib/yaml";
const temporaryDirectories: string[] = [];
async function temporaryDirectory(): Promise<string> {
const path = await mkdtemp(join(tmpdir(), "kuber-test-"));
temporaryDirectories.push(path);
return path;
}
afterEach(async () => {
await Promise.all(
temporaryDirectories
.splice(0)
.map((path) => rm(path, { recursive: true, force: true })),
);
});
describe("Compose file discovery", () => {
test("finds supported names and chooses lexical precedence", async () => {
const directory = await temporaryDirectory();
await Promise.all([
writeFile(join(directory, "docker-compose.yml"), "services: {}\n"),
writeFile(join(directory, "compose.yaml"), "services: {}\n"),
writeFile(join(directory, "ignored.yml"), "services: {}\n"),
]);
expect(await resolveComposeFile(directory)).toBe(
join(directory, "compose.yaml"),
);
});
test("ignores directories with Compose-looking names", async () => {
const directory = await temporaryDirectory();
await mkdir(join(directory, "compose.yml"));
expect(await resolveComposeFile(directory)).toBeUndefined();
});
test("returns undefined when no supported file exists", async () => {
const directory = await temporaryDirectory();
await writeFile(join(directory, "stack.yml"), "services: {}\n");
expect(await resolveComposeFile(directory)).toBeUndefined();
});
});
describe("Compose parsing", () => {
test("accepts the generated marker and preserves x- extensions", async () => {
const directory = await temporaryDirectory();
const path = join(directory, "compose.yml");
await writeFile(
path,
"managedBy: kuber # See https://npmx.dev/@dmgnr/kuber for documentation.\nname: compose-project\nx-note: retained\nservices:\n app:\n image: nginx:latest\n",
);
expect(await readCompose(path)).toMatchObject({
managedBy: "kuber",
name: "compose-project",
"x-note": "retained",
services: { app: { image: "nginx:latest" } },
});
});
test("rejects incorrect managedBy values", async () => {
const directory = await temporaryDirectory();
const path = join(directory, "compose.yml");
for (const marker of ["other", "42"]) {
await writeFile(path, `managedBy: ${marker}\nservices: {}\n`);
await expect(readCompose(path)).rejects.toThrow();
}
});
test("rejects other unknown top-level properties", async () => {
const directory = await temporaryDirectory();
const path = join(directory, "compose.yml");
await writeFile(path, "managedBy: kuber\nunknown: value\nservices: {}\n");
await expect(readCompose(path)).rejects.toThrow();
});
test("parses and validates a minimal Compose project", async () => {
const directory = await temporaryDirectory();
const path = join(directory, "compose.yml");
await writeFile(
path,
"name: compose-project\nservices:\n app:\n image: nginx:latest\n",
);
expect(await readCompose(path)).toMatchObject({
name: "compose-project",
services: { app: { image: "nginx:latest" } },
});
});
test("rejects malformed YAML", async () => {
const directory = await temporaryDirectory();
const path = join(directory, "compose.yml");
await writeFile(path, "services: [\n");
await expect(readCompose(path)).rejects.toThrow();
});
test("rejects schema-invalid service values", async () => {
const directory = await temporaryDirectory();
const path = join(directory, "compose.yml");
await writeFile(path, "services:\n app: 42\n");
await expect(readCompose(path)).rejects.toThrow();
});
});