import { describe, it, expect, vi } from "vitest"; import { recordSpanException } from "../src/v3/otel/utils.js"; import type { Span } from "@opentelemetry/api"; function createMockSpan() { return { recordException: vi.fn(), setStatus: vi.fn(), } as unknown as Span & { recordException: ReturnType; setStatus: ReturnType; }; } describe("recordSpanException", () => { it("records Error instances with truncated message and stack", () => { const span = createMockSpan(); const error = new Error("x".repeat(5_000)); recordSpanException(span, error); expect(span.recordException).toHaveBeenCalledTimes(1); const recorded = (span.recordException as any).mock.calls[0][0] as Error; expect(recorded).toBeInstanceOf(Error); expect(recorded.message.length).toBeLessThan(1100); }); it("records string errors with truncation", () => { const span = createMockSpan(); recordSpanException(span, "x".repeat(10_000)); const recorded = (span.recordException as any).mock.calls[0][0] as string; expect(typeof recorded).toBe("string"); expect(recorded.length).toBeLessThan(5_100); expect(recorded).toContain("...[truncated]"); }); it("does not throw on circular references", () => { const span = createMockSpan(); const circular: any = { foo: "bar" }; circular.self = circular; expect(() => recordSpanException(span, circular)).not.toThrow(); expect(span.recordException).toHaveBeenCalledTimes(1); expect(span.setStatus).toHaveBeenCalledTimes(1); }); it("does not throw on BigInt values", () => { const span = createMockSpan(); const error = { count: BigInt(123) }; expect(() => recordSpanException(span, error)).not.toThrow(); expect(span.recordException).toHaveBeenCalledTimes(1); }); it("handles symbol values (JSON.stringify returns undefined)", () => { const span = createMockSpan(); const sym = Symbol("test"); expect(() => recordSpanException(span, sym)).not.toThrow(); expect(span.recordException).toHaveBeenCalledTimes(1); const recorded = (span.recordException as any).mock.calls[0][0] as string; expect(typeof recorded).toBe("string"); expect(recorded).toContain("Symbol"); }); it("handles function values (JSON.stringify returns undefined)", () => { const span = createMockSpan(); const fn = () => "test"; expect(() => recordSpanException(span, fn)).not.toThrow(); expect(span.recordException).toHaveBeenCalledTimes(1); }); it("handles undefined (JSON.stringify returns undefined)", () => { const span = createMockSpan(); expect(() => recordSpanException(span, undefined)).not.toThrow(); expect(span.recordException).toHaveBeenCalledTimes(1); const recorded = (span.recordException as any).mock.calls[0][0] as string; expect(typeof recorded).toBe("string"); }); it("always calls setStatus ERROR", () => { const span = createMockSpan(); recordSpanException(span, new Error("test")); recordSpanException(span, "string"); recordSpanException(span, { obj: true }); expect(span.setStatus).toHaveBeenCalledTimes(3); }); });