diff --git a/packages/cli/src/__tests__/billing-guidance.test.ts b/packages/cli/src/__tests__/billing-guidance.test.ts index 32b40712..3c5d5273 100644 --- a/packages/cli/src/__tests__/billing-guidance.test.ts +++ b/packages/cli/src/__tests__/billing-guidance.test.ts @@ -1,6 +1,6 @@ import type { BillingGuidanceDeps } from "../shared/billing-guidance"; -import { beforeEach, describe, expect, it, mock, spyOn } from "bun:test"; +import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from "bun:test"; import { handleBillingError, isBillingError, showNonBillingError } from "../shared/billing-guidance"; // ── Mock deps (injected via DI, not mock.module) ────────────────────────── @@ -101,20 +101,22 @@ describe("handleBillingError", () => { mockPrompt.mockClear(); }); + afterEach(() => { + stderrSpy.mockRestore(); + }); + it("opens billing URL and returns true when user presses Enter", async () => { mockPrompt.mockImplementation(() => Promise.resolve("")); const deps = createMockDeps(); const result = await handleBillingError("hetzner", deps); expect(result).toBe(true); expect(deps.openBrowser).toHaveBeenCalledWith("https://console.hetzner.cloud/"); - stderrSpy.mockRestore(); }); it("returns false when prompt throws (Ctrl+C)", async () => { mockPrompt.mockImplementation(() => Promise.reject(new Error("cancelled"))); const result = await handleBillingError("digitalocean", createMockDeps()); expect(result).toBe(false); - stderrSpy.mockRestore(); }); it("works for clouds without billing URL", async () => { @@ -123,7 +125,6 @@ describe("handleBillingError", () => { const result = await handleBillingError("unknown", deps); expect(result).toBe(true); expect(deps.openBrowser).not.toHaveBeenCalled(); - stderrSpy.mockRestore(); }); }); @@ -134,6 +135,10 @@ describe("showNonBillingError", () => { stderrSpy = spyOn(process.stderr, "write").mockImplementation(() => true); }); + afterEach(() => { + stderrSpy.mockRestore(); + }); + it("does not throw", () => { const deps = createMockDeps(); expect(() => { @@ -145,6 +150,5 @@ describe("showNonBillingError", () => { deps, ); }).not.toThrow(); - stderrSpy.mockRestore(); }); }); diff --git a/packages/cli/src/__tests__/cloud-init.test.ts b/packages/cli/src/__tests__/cloud-init.test.ts index f22eb905..c53b2de9 100644 --- a/packages/cli/src/__tests__/cloud-init.test.ts +++ b/packages/cli/src/__tests__/cloud-init.test.ts @@ -47,44 +47,68 @@ describe("getPackagesForTier", () => { }); describe("needsNode", () => { - it("returns true for 'node' tier", () => { - expect(needsNode("node")).toBe(true); - }); - - it("returns true for 'full' tier", () => { - expect(needsNode("full")).toBe(true); - }); - - it("returns false for 'minimal' tier", () => { - expect(needsNode("minimal")).toBe(false); - }); - - it("returns false for 'bun' tier", () => { - expect(needsNode("bun")).toBe(false); - }); - + const cases: Array< + [ + Parameters[0], + boolean, + ] + > = [ + [ + "node", + true, + ], + [ + "full", + true, + ], + [ + "minimal", + false, + ], + [ + "bun", + false, + ], + ]; + for (const [tier, expected] of cases) { + it(`returns ${expected} for '${tier}' tier`, () => { + expect(needsNode(tier)).toBe(expected); + }); + } it("defaults to true (full tier)", () => { expect(needsNode()).toBe(true); }); }); describe("needsBun", () => { - it("returns true for 'bun' tier", () => { - expect(needsBun("bun")).toBe(true); - }); - - it("returns true for 'full' tier", () => { - expect(needsBun("full")).toBe(true); - }); - - it("returns false for 'minimal' tier", () => { - expect(needsBun("minimal")).toBe(false); - }); - - it("returns false for 'node' tier", () => { - expect(needsBun("node")).toBe(false); - }); - + const cases: Array< + [ + Parameters[0], + boolean, + ] + > = [ + [ + "bun", + true, + ], + [ + "full", + true, + ], + [ + "minimal", + false, + ], + [ + "node", + false, + ], + ]; + for (const [tier, expected] of cases) { + it(`returns ${expected} for '${tier}' tier`, () => { + expect(needsBun(tier)).toBe(expected); + }); + } it("defaults to true (full tier)", () => { expect(needsBun()).toBe(true); }); diff --git a/packages/cli/src/__tests__/junie-agent.test.ts b/packages/cli/src/__tests__/junie-agent.test.ts index 5ac26266..69bcd682 100644 --- a/packages/cli/src/__tests__/junie-agent.test.ts +++ b/packages/cli/src/__tests__/junie-agent.test.ts @@ -8,7 +8,7 @@ * - cloudInitTier is 'node' (npm-installed agent) */ -import { beforeEach, describe, expect, it, mock, spyOn } from "bun:test"; +import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from "bun:test"; // ── Suppress stderr output from logStep/logError during tests ──────────────── @@ -18,6 +18,10 @@ beforeEach(() => { stderrSpy = spyOn(process.stderr, "write").mockImplementation(() => true); }); +afterEach(() => { + stderrSpy.mockRestore(); +}); + // ── Import module under test ────────────────────────────────────────────────── // agent-setup.ts doesn't import oauth, so no mock needed.