import { afterEach, expect, test } from "bun:test"; import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { updateApp } from "../src/update.ts"; const roots: string[] = []; afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); }); const CONFIG = `export default { compatibilityDate: "2026-08-02", frameworkBehaviour: 1, functions: { legacyDefaultRuntime: "current" }, compatibility: { legacyEmit: false, stringLayouts: false }, observability: { sampleRate: 1 }, }; `; const NESTED_CONFIG = `export default { compatibilityDate: "2026-08-02", frameworkBehaviour: 1, functions: { legacyDefaultRuntime: "current", overrides: { a: { b: 1 } } }, compatibility: { legacyEmit: false, nested: { deeper: { value: true } } }, observability: { sampleRate: 1 }, }; `; function project(config = CONFIG): string { const root = mkdtempSync(join(tmpdir(), "wrnexus-migrate-")); roots.push(root); mkdirSync(join(root, "app"), { recursive: true }); writeFileSync( join(root, "package.json"), JSON.stringify({ name: "config-migrate-app", dependencies: { "@wrnexus/core": "^0.8.0" }, wrnexus: { version: "0.8.0" }, }), ); writeFileSync(join(root, "wrnexus.config.ts"), config); return root; } test("the removed keys are deleted and the rest is kept", () => { const root = project(); updateApp(root, "0.9.0", false); const config = readFileSync(join(root, "wrnexus.config.ts"), "utf8"); expect(config).not.toContain("compatibilityDate"); expect(config).not.toContain("frameworkBehaviour"); expect(config).not.toContain("legacyDefaultRuntime"); expect(config).not.toContain("legacyEmit"); expect(config).toContain("observability"); }); test("running it twice changes nothing the second time", () => { const root = project(); updateApp(root, "0.9.0", false); const once = readFileSync(join(root, "wrnexus.config.ts"), "utf8"); updateApp(root, "0.9.0", false); expect(readFileSync(join(root, "wrnexus.config.ts"), "utf8")).toBe(once); }); test("a dry run writes nothing", () => { const root = project(); updateApp(root, "0.9.0", true); expect(readFileSync(join(root, "wrnexus.config.ts"), "utf8")).toBe(CONFIG); }); test("a nested object value under a removed key does not corrupt the file", () => { const root = project(NESTED_CONFIG); updateApp(root, "0.9.0", false); const config = readFileSync(join(root, "wrnexus.config.ts"), "utf8"); expect(config).not.toContain("compatibilityDate"); expect(config).not.toContain("frameworkBehaviour"); expect(config).not.toContain("legacyDefaultRuntime"); expect(config).not.toContain("legacyEmit"); expect(config).not.toContain("overrides"); expect(config).not.toContain("nested"); expect(config).toContain("observability"); // The file must remain valid, balanced TypeScript: an equal number of // opening and closing braces, and it must still be parseable as a module. const opens = (config.match(/\{/g) ?? []).length; const closes = (config.match(/\}/g) ?? []).length; expect(opens).toBe(closes); });