import { describe, expect, mock, test } from "bun:test"; import z from "zod"; import { formatUnknownError, wrapCommandErrors } from "../../lib/error"; describe("CLI error handling", () => { test("formats Zod errors without exposing internal parser details", () => { const error = z.object({ name: z.string() }).safeParse({ name: 1 }).error; expect(formatUnknownError(error)).toContain("name"); expect(formatUnknownError(error)).toContain("expected string"); }); test("catches errors from nested command handlers before Citty sees them", async () => { const handleError = mock((_error: unknown) => {}); const command = { subCommands: { child: { async run() { throw new Error("command failed"); }, }, }, }; wrapCommandErrors(command, handleError); await expect(command.subCommands.child.run()).resolves.toBeUndefined(); expect(handleError).toHaveBeenCalledTimes(1); expect(handleError.mock.calls[0]?.[0]).toBeInstanceOf(Error); expect(String(handleError.mock.calls[0]?.[0])).toContain("command failed"); }); test("formats a dispatched command error once and exits with code 1", async () => { const process = Bun.spawn(["bun", "index.ts", "exec"], { cwd: `${import.meta.dir}/../..`, stdout: "pipe", stderr: "pipe", }); const [stderr, exitCode] = await Promise.all([ new Response(process.stderr).text(), process.exited, ]); expect(exitCode).toBe(1); expect(stderr.match(/Deployment name is required/g)).toHaveLength(1); }); });