import { describe, expect, it, vi } from "vitest"; import { AppError, asError, isAppError, toErrorPayload } from "../src/lib/errors.js"; import { createLogger } from "../src/lib/logger.js"; describe("logger", () => { it("writes JSON logs using provided sink", () => { const sink = vi.fn<(line: string) => void>(); const logger = createLogger({ name: "unit", sink, now: () => new Date("2026-01-01T00:00:00.000Z") }); logger.info("ready", { port: 3000 }); expect(sink).toHaveBeenCalledTimes(1); expect(JSON.parse(sink.mock.calls[0][0] as string)).toEqual({ timestamp: "2026-01-01T00:00:00.000Z", level: "info", logger: "unit", message: "ready", details: { port: 3000 } }); }); it("defaults to stderr and never writes to stdout", () => { const stderrWrite = vi .spyOn(process.stderr, "write") .mockImplementation(() => true); const stdoutWrite = vi .spyOn(process.stdout, "write") .mockImplementation(() => true); const logger = createLogger({ name: "unit" }); logger.error("failed"); expect(stderrWrite).toHaveBeenCalledTimes(1); expect(stdoutWrite).not.toHaveBeenCalled(); stderrWrite.mockRestore(); stdoutWrite.mockRestore(); }); }); describe("errors", () => { it("normalizes unknown values into Error", () => { expect(asError("boom")).toBeInstanceOf(Error); expect(asError("boom").message).toBe("boom"); expect(asError(123).message).toBe("Unknown error"); }); it("exposes consistent payloads", () => { const appError = new AppError("Bad input", "BAD_INPUT"); expect(isAppError(appError)).toBe(true); expect(toErrorPayload(appError)).toEqual({ name: "AppError", message: "Bad input", code: "BAD_INPUT" }); expect(toErrorPayload(new Error("Oops"))).toEqual({ name: "Error", message: "Oops" }); }); });