import { describe, expect, test } from "bun:test"; import { join } from "node:path"; const repoRoot = join(import.meta.dir, "..", "..", ".."); const entry = join(repoRoot, "packages", "bin", "src", "index.ts"); async function runKitchen(args: string[]) { const proc = Bun.spawn(["bun", entry, ...args], { cwd: repoRoot, stdout: "pipe", stderr: "pipe", }); const [stdout, stderr] = await Promise.all([ new Response(proc.stdout).text(), new Response(proc.stderr).text(), ]); const exitCode = await proc.exited; return { exitCode, stdout, stderr }; } describe("kitchen CLI (e2e)", () => { test("view renders a recipe file to stdout and exits 0", async () => { const { exitCode, stdout, stderr } = await runKitchen(["view", "fixtures/prose.md"]); const out = Bun.stripANSI(stdout); expect(exitCode).toBe(0); expect(stderr).toBe(""); expect(out).toContain("Buttered Toast"); expect(out).toContain("Method"); expect(out).toContain("Serving"); expect(out).toContain("Cut into triangles and serve at once."); }); test("view preserves document order in the output", async () => { const { stdout } = await runKitchen(["view", "fixtures/prose.md"]); const out = Bun.stripANSI(stdout); expect(out.indexOf("Method")).toBeLessThan(out.indexOf("Serving")); }); test("ANSI styling is suppressed when stdout is not a TTY (piped)", async () => { const { stdout } = await runKitchen(["view", "fixtures/prose.md"]); expect(stdout).not.toContain("\x1b"); }); test("a nonexistent file prints a human-readable error to stderr and exits 1", async () => { const { exitCode, stdout, stderr } = await runKitchen(["view", "does/not/exist.md"]); expect(exitCode).toBe(1); expect(stdout).toBe(""); expect(stderr).toContain("cannot read"); expect(stderr).toContain("does/not/exist.md"); expect(stderr.startsWith("kitchen:")).toBe(true); }); test("a missing file argument prints usage to stderr and exits 1", async () => { const { exitCode, stderr } = await runKitchen(["view"]); expect(exitCode).toBe(1); expect(stderr).not.toBe(""); expect(stderr.toLowerCase()).toContain("missing required argument"); }); test("--help lists the view command and exits 0", async () => { const { exitCode, stdout } = await runKitchen(["--help"]); expect(exitCode).toBe(0); expect(stdout).toContain("view"); }); });