import { describe, test, expect, beforeAll, afterAll } from "vitest" import { existsSync, readFileSync, rmSync, mkdirSync } from "node:fs" import path from "node:path" import os from "node:os" import { fileURLToPath } from "node:url" import { spawnSync } from "node:child_process" const __dirname = path.dirname(fileURLToPath(import.meta.url)) const DRAW_IMAGE_DIR = path.resolve(__dirname, "..") const TMP = path.join(os.tmpdir(), `draw-image-idempotency-${process.pid}`) beforeAll(() => { if (existsSync(TMP)) rmSync(TMP, { recursive: true, force: true }) mkdirSync(TMP, { recursive: true }) }) afterAll(() => { if (existsSync(TMP)) rmSync(TMP, { recursive: true, force: true }) }) function renderCli(template: string, title: string, out: string, slots?: string): { status: number; stdout: string; stderr: string } { const args = ["--experimental-strip-types", path.join(DRAW_IMAGE_DIR, "cli.ts"), "render", template, "--title", title, "--out", out, "--template-dir", "tests/fixtures"] if (slots) args.push("--slots", slots) return spawnSync("node", args, { encoding: "utf-8", cwd: DRAW_IMAGE_DIR }) } describe("integration — idempotency", () => { test("re-render with same args skips", () => { const out = path.join(TMP, "cover.png") const r1 = renderCli("cover", "Same Title", out) expect(r1.status).toBe(0) const result1 = JSON.parse(r1.stdout) expect(result1.status).toBe("rendered") const r2 = renderCli("cover", "Same Title", out) expect(r2.status).toBe(0) const result2 = JSON.parse(r2.stdout) expect(result2.status).toBe("skipped") }) test("changed title re-renders", () => { const out = path.join(TMP, "cover2.png") const r1 = renderCli("cover", "Title A", out) const result1 = JSON.parse(r1.stdout) expect(result1.status).toBe("rendered") const r2 = renderCli("cover", "Title B", out) const result2 = JSON.parse(r2.stdout) expect(result2.status).toBe("rendered") const meta = JSON.parse(readFileSync(out.replace(/\.png$/, ".meta.json"), "utf-8")) expect(meta.hash).toHaveLength(64) }) })