// packages/core-shared/src/instrumentation/di/bind-otel-instrumentation.test.ts import "reflect-metadata"; import { describe, it, expect, vi, beforeEach } from "vitest"; vi.mock("@sentry/nextjs", () => ({ init: vi.fn(), captureException: vi.fn(), captureMessage: vi.fn(), addBreadcrumb: vi.fn(), setUser: vi.fn(), })); import { Container } from "inversify"; import { bindOtelInstrumentation } from "@/instrumentation/di/bind-otel-instrumentation"; import { INSTRUMENTATION_SYMBOLS } from "@/instrumentation/symbols"; import { OtelTracer } from "@/instrumentation/otel/otel-tracer"; import { OtelLogger } from "@/instrumentation/otel/otel-logger"; // NOTE: initOtelServerNode is intentionally NOT called by bindOtelInstrumentation. // The SDK is initialized by each app's instrumentation.ts register() hook so PII // scrub processors are active before the first request (C1 fix). There is therefore // no initOtelServerNode mock or call-count assertion here. describe("bindOtelInstrumentation", () => { beforeEach(() => { vi.clearAllMocks(); }); it("binds OtelTracer + OtelLogger to the container", () => { const c = new Container(); bindOtelInstrumentation(c, { dsn: "https://x@y/1", app: "web-next" }); expect(c.get(INSTRUMENTATION_SYMBOLS.TRACER)).toBeInstanceOf(OtelTracer); expect(c.get(INSTRUMENTATION_SYMBOLS.LOGGER)).toBeInstanceOf(OtelLogger); }); it("returns the tracer + logger instances", () => { const c = new Container(); const { tracer, logger } = bindOtelInstrumentation(c, { dsn: "https://x@y/1", app: "web-next", }); expect(tracer).toBeInstanceOf(OtelTracer); expect(logger).toBeInstanceOf(OtelLogger); }); it("rebinds when called a second time (idempotent container state)", () => { const c = new Container(); bindOtelInstrumentation(c, { dsn: "https://x@y/1", app: "web-next" }); // Second call should not throw even if TRACER is already bound. expect(() => bindOtelInstrumentation(c, { dsn: "https://x@y/2", app: "cms" }), ).not.toThrow(); expect(c.get(INSTRUMENTATION_SYMBOLS.TRACER)).toBeInstanceOf(OtelTracer); }); });