Files
WRNexusJS/packages/observability/test/integrations.test.ts

107 lines
3.5 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import { MetricsRegistry } from "../src/metrics.ts";
import {
createOperationTracer,
createOtlpLogExporter,
createPerformanceProfiler,
createPrometheusPushExporter,
createSentryCompatibleReporter,
createZipkinExporter,
renderPrometheus,
} from "../src/integrations.ts";
describe("observability integrations", () => {
test("records every framework operation kind and failures", async () => {
const spans: any[] = [];
const tracer = createOperationTracer({
exporter: {
export: (records) => {
spans.push(...records);
},
},
now: (() => {
let time = 0;
return () => (time += 5);
})(),
});
for (const kind of [
"database",
"cache",
"queue",
"realtime",
"server-action",
"application",
] as const)
expect(await tracer.span(kind, `${kind}.work`, async () => kind)).toBe(kind);
await expect(
tracer.span("application", "failure", async () => {
throw new Error("boom");
}),
).rejects.toThrow("boom");
expect(spans.map((span) => span.attributes["wrnexus.span.kind"])).toContain("database");
expect(spans.at(-1).status).toBe("error");
});
test("exports Prometheus, Zipkin/Jaeger, OTLP logs and Sentry-compatible errors", async () => {
const requests: Array<{ url: string; init?: RequestInit }> = [];
const send = (async (url: URL | RequestInfo, init?: RequestInit) => {
requests.push({ url: String(url), init });
return new Response(null, { status: 200 });
}) as typeof fetch;
const registry = new MetricsRegistry(() => 10);
registry.increment("http.requests", 1, { route: "/" });
expect(renderPrometheus(registry.snapshot())).toContain('http_requests{route="/"} 1');
await createPrometheusPushExporter("https://prom.test", { fetch: send }).export(
registry.snapshot(),
);
const span = {
name: "db",
traceId: "1".repeat(32),
spanId: "2".repeat(16),
sampled: true,
startTime: 1,
endTime: 2,
durationMs: 1,
status: "ok" as const,
attributes: {},
};
await createZipkinExporter("https://zipkin.test", { fetch: send }).export([span]);
await createOtlpLogExporter("https://otlp.test", { fetch: send }).export([
{
timestamp: new Date(0).toISOString(),
level: "info",
message: "ready",
service: "app",
attributes: {},
},
]);
expect(
await createSentryCompatibleReporter("https://sentry.test", { fetch: send }).capture(
new Error("bad"),
),
).toHaveLength(32);
expect(requests).toHaveLength(4);
});
test("profiles application operations", async () => {
const profiles: any[] = [];
let time = 0;
const profile = createPerformanceProfiler({
now: () => (time += 4),
onProfile: (value) => profiles.push(value),
});
expect(await profile("render", () => "ok")).toBe("ok");
expect(profiles[0]).toMatchObject({ name: "render", durationMs: 4 });
});
test("operation exporter failures reach diagnostics without recursive telemetry", async () => {
const diagnostics: string[] = [];
const tracer = createOperationTracer({
exporter: { export: () => Promise.reject(new Error("offline")) },
diagnostic: (message) => diagnostics.push(message),
});
await expect(tracer.span("database", "query", async () => 1)).resolves.toBe(1);
expect(diagnostics).toEqual(["operation span export failed"]);
});
});