import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; import { existsSync } from "node:fs"; import { tmpdir } from "node:os"; import { dirname, join, resolve } from "node:path"; import { describe, expect, it } from "vitest"; import { runEditorPack } from "../src/pack.js"; const FIXTURE_FILES: Record = { "content/time.yaml": [ "id: default", "dayLengthTicks: 240", "seasons:", " - { name: spring, dayCount: 14 }", "start: { day: 1, season: spring }", "", ].join("\n"), "content/maps/farm.yaml": [ "id: farm", "width: 12", "height: 12", "tilesetRef: farm-tiles", "spawn: { x: 2, y: 2 }", "walkable:", " water: false", "layers:", " - name: ground", " data:", ...mapRows(), "", ].join("\n"), "content/items/hoe.yaml": [ "id: hoe", "name: Hoe", "kind: tool", "stackable: false", "price: 100", "use: tills a soil tile", "", ].join("\n"), }; function mapRows(): string[] { const rows: string[] = []; for (let y = 0; y < 12; y++) { const row: string[] = []; for (let x = 0; x < 12; x++) { row.push(x < 2 && y < 2 ? "water" : "grass"); } rows.push(` - [${row.join(", ")}]`); } return rows; } async function fixtureDir(): Promise { const dir = await mkdtemp(join(tmpdir(), "editor-pack-")); for (const [rel, content] of Object.entries(FIXTURE_FILES)) { const target = join(dir, rel); await mkdir(dirname(target), { recursive: true }); await writeFile(target, content, "utf8"); } return dir; } async function rmRecursive(dir: string): Promise { await rm(dir, { recursive: true, force: true }); } function options(overrides: Partial<{ desktop: boolean; installer: boolean; mods: boolean; splitAssets: boolean }> = {}): Parameters[1] { return { name: "Pinefield Valley", icon: "", desktop: overrides.desktop ?? false, installer: overrides.installer ?? false, mods: overrides.mods ?? false, splitAssets: overrides.splitAssets ?? false, outDir: "", }; } describe("runEditorPack (E7 package dialog pipeline)", () => { it("packs a minimal fixture project into a static site + bundle.json", async () => { const dir = await fixtureDir(); try { const result = await runEditorPack(dir, options(), existsSync(join(dir, "mods"))); expect(result.ok).toBe(true); if (!result.ok) return; expect(result.outDir).toBe(resolve(dir, "dist-pack")); expect(existsSync(join(result.outDir, "bundle.json"))).toBe(true); expect(existsSync(join(result.outDir, "index.html"))).toBe(true); expect(existsSync(join(result.outDir, "assets"))).toBe(true); expect(result.stats.kinds).toBeGreaterThan(0); expect(result.stats.defCount).toBeGreaterThan(0); expect(result.stats.desktop).toBe(false); expect(result.stats.installer).toBe(false); } finally { await rmRecursive(dir); } }); it("desktop mode writes the Electron shell (main.cjs + package.json)", async () => { const dir = await fixtureDir(); try { const result = await runEditorPack(dir, options({ desktop: true }), existsSync(join(dir, "mods"))); expect(result.ok).toBe(true); if (!result.ok) return; expect(result.stats.desktop).toBe(true); expect(existsSync(join(result.outDir, "desktop", "main.cjs"))).toBe(true); expect(existsSync(join(result.outDir, "desktop", "package.json"))).toBe(true); expect(existsSync(join(result.outDir, "desktop", "README-desktop.md"))).toBe(true); } finally { await rmRecursive(dir); } }); it("installer mode writes electron-builder.yml and copies the site into desktop/", async () => { const dir = await fixtureDir(); try { const result = await runEditorPack(dir, options({ installer: true }), existsSync(join(dir, "mods"))); expect(result.ok).toBe(true); if (!result.ok) return; expect(result.stats.installer).toBe(true); expect(result.stats.desktop).toBe(true); expect(existsSync(join(result.outDir, "desktop", "electron-builder.yml"))).toBe(true); expect(existsSync(join(result.outDir, "desktop", "index.html"))).toBe(true); expect(existsSync(join(result.outDir, "desktop", "bundle.json"))).toBe(true); expect(existsSync(join(result.outDir, "desktop", "assets"))).toBe(true); } finally { await rmRecursive(dir); } }); it("surfaces a content-compile failure as {ok: false, error} with the per-def message", async () => { const dir = await mkdtemp(join(tmpdir(), "editor-pack-bad-")); try { await mkdir(join(dir, "content", "maps"), { recursive: true }); await writeFile(join(dir, "content", "maps", "bad.yaml"), ["id: bad", "width: nope", "height: 2", ""].join("\n")); const result = await runEditorPack(dir, options(), false); expect(result.ok).toBe(false); if (result.ok) return; expect(result.error).toContain("validation failed"); expect(result.error).toContain("map/bad"); } finally { await rmRecursive(dir); } }); });