import { expect, test, vi } from "vitest" import { createTaggedErrorClass, isTaggedError } from "#Source/exception/index.ts" test("createTaggedErrorClass creates tagged errors with inferred message, cause and serialization", () => { const dateNowSpy = vi.spyOn(Date, "now").mockReturnValue(123) try { const ExampleErrorClass = createTaggedErrorClass("Example")<{ message: string cause: Error extra: number }>() const MessageOnlyErrorClass = createTaggedErrorClass("MessageOnly")() const cause = new Error("root") cause.stack = "Error: root\n at cause" const example1 = new ExampleErrorClass({ message: "boom", cause, extra: 1, }) const example2 = new MessageOnlyErrorClass("plain-message") const example3 = ExampleErrorClass.is(example1) const example4 = ExampleErrorClass.is( new (createTaggedErrorClass("Example")<{ message: string }>())({ message: "compatible", }), ) const example5 = example1.toJSON() expect(example1).toBeInstanceOf(Error) expect(example1.name).toBe("Example") expect(example1.tag).toBe("Example") expect(example1.data.extra).toBe(1) expect(example1.message).toBe("boom") expect(example1.cause).toBe(cause) expect(example1.stack).toContain("Caused by: Error: root") expect(example2.message).toBe("plain-message") expect(example3).toBe(true) expect(example4).toBe(true) expect(example5).toMatchObject({ version: "1", tag: "Example", data: { message: "boom", cause, extra: 1, }, name: "Example", message: "boom", cause: { name: "Error", message: "root", stack: "Error: root\n at cause", }, timestamp: 123, }) } finally { dateNowSpy.mockRestore() } }) test("isTaggedError distinguishes tagged errors from plain values", () => { const ExampleError = createTaggedErrorClass("Example")<{ message: string }>() const example1 = new ExampleError({ message: "boom" }) const example2 = new Error("boom") const example3 = { tag: "Example", data: { message: "boom" }, toJSON: () => ({ message: "boom" }), } expect(isTaggedError(example1)).toBe(true) expect(isTaggedError(example2)).toBe(false) expect(isTaggedError(example3)).toBe(false) expect(isTaggedError(null)).toBe(false) })