62 lines
2.2 KiB
TypeScript
62 lines
2.2 KiB
TypeScript
import { test, expect } from "bun:test";
|
|
import { createContext } from "@wrnexus/core";
|
|
import { createTracker, type ErrorEvent, type ErrorSink } from "../src/index.ts";
|
|
|
|
function collectingSink(): ErrorSink & { events: ErrorEvent[] } {
|
|
const events: ErrorEvent[] = [];
|
|
return { name: "collect", events, capture: (e) => void events.push(e) };
|
|
}
|
|
|
|
test("capture fans out to sinks with context + timestamp", async () => {
|
|
const sink = collectingSink();
|
|
const tracker = createTracker({ sinks: [sink], now: () => 123 });
|
|
await tracker.capture(new Error("boom"), { userId: "u1" });
|
|
expect(sink.events.length).toBe(1);
|
|
expect(sink.events[0]!.error.message).toBe("boom");
|
|
expect(sink.events[0]!.context.userId).toBe("u1");
|
|
expect(sink.events[0]!.timestamp).toBe(123);
|
|
});
|
|
|
|
test("non-Error values are wrapped", async () => {
|
|
const sink = collectingSink();
|
|
const tracker = createTracker({ sinks: [sink] });
|
|
await tracker.capture("just a string");
|
|
expect(sink.events[0]!.error.message).toBe("just a string");
|
|
});
|
|
|
|
test("beforeSend can scrub or drop events", async () => {
|
|
const sink = collectingSink();
|
|
const tracker = createTracker({
|
|
sinks: [sink],
|
|
beforeSend: (e) => (e.context.secret ? null : e), // drop events tagged secret
|
|
});
|
|
await tracker.capture(new Error("a"), { secret: true });
|
|
await tracker.capture(new Error("b"));
|
|
expect(sink.events.map((e) => e.error.message)).toEqual(["b"]);
|
|
});
|
|
|
|
test("middleware captures a thrown request error and re-throws it", async () => {
|
|
const sink = collectingSink();
|
|
const tracker = createTracker({ sinks: [sink] });
|
|
const url = new URL("http://x/api/boom");
|
|
const ctx = createContext(new Request(url, { method: "POST" }), url);
|
|
await expect(
|
|
tracker.middleware()(ctx, () => {
|
|
throw new Error("downstream");
|
|
}),
|
|
).rejects.toThrow("downstream");
|
|
expect(sink.events[0]!.context).toMatchObject({ method: "POST", path: "/api/boom" });
|
|
});
|
|
|
|
test("a failing sink never breaks capture", async () => {
|
|
const bad: ErrorSink = {
|
|
capture: () => {
|
|
throw new Error("sink down");
|
|
},
|
|
};
|
|
const good = collectingSink();
|
|
const tracker = createTracker({ sinks: [bad, good] });
|
|
await tracker.capture(new Error("x")); // must not throw
|
|
expect(good.events.length).toBe(1);
|
|
});
|