diff --git a/apps/web-next/src/server/bind-production.test.ts b/apps/web-next/src/server/bind-production.test.ts index f4c8ca8..ebfff8e 100644 --- a/apps/web-next/src/server/bind-production.test.ts +++ b/apps/web-next/src/server/bind-production.test.ts @@ -11,6 +11,14 @@ vi.mock("@repo/auth/di/bind-dev-seed", () => ({ bindDevSeedAuth: vi.fn() })); vi.mock("@repo/marketing-pages/di/bind-dev-seed", () => ({ bindDevSeedMarketingPages: vi.fn() })); vi.mock("@repo/navigation/di/bind-dev-seed", () => ({ bindDevSeedNavigation: vi.fn() })); vi.mock("@repo/media/di/bind-dev-seed", () => ({ bindDevSeedMedia: vi.fn() })); +vi.mock("@repo/core-shared/instrumentation", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + bindSentryInstrumentation: vi.fn(actual.bindSentryInstrumentation), + bindNoopInstrumentation: vi.fn(actual.bindNoopInstrumentation), + }; +}); describe("bindAllProduction", () => { beforeEach(() => { @@ -105,3 +113,69 @@ describe("bindAll dispatcher", () => { expect(bindDevSeedBlog).not.toHaveBeenCalled(); }); }); + +describe("bindAll instrumentation orthogonality (Rule 0, R47)", () => { + beforeEach(() => { + vi.resetModules(); + vi.clearAllMocks(); + vi.unstubAllEnvs(); + }); + + afterEach(() => { + vi.unstubAllEnvs(); + }); + + it("DSN absent → bindNoopInstrumentation regardless of NODE_ENV (R48)", async () => { + vi.stubEnv("WEB_NEXT_SENTRY_DSN", ""); + vi.stubEnv("NODE_ENV", "production"); + const { bindAll } = await import("./bind-production"); + const { bindNoopInstrumentation, bindSentryInstrumentation } = await import( + "@repo/core-shared/instrumentation" + ); + + await bindAll(); + + expect(bindNoopInstrumentation).toHaveBeenCalledOnce(); + expect(bindSentryInstrumentation).not.toHaveBeenCalled(); + }); + + it("DSN set → bindSentryInstrumentation regardless of NODE_ENV", async () => { + vi.stubEnv("WEB_NEXT_SENTRY_DSN", "https://x@y/1"); + vi.stubEnv("NODE_ENV", "development"); + const { bindAll } = await import("./bind-production"); + const { bindNoopInstrumentation, bindSentryInstrumentation } = await import( + "@repo/core-shared/instrumentation" + ); + + await bindAll(); + + expect(bindSentryInstrumentation).toHaveBeenCalledOnce(); + expect(bindNoopInstrumentation).not.toHaveBeenCalled(); + }); + + it("Sentry instrumentation works alongside dev seed (USE_DEV_SEED=true)", async () => { + vi.stubEnv("USE_DEV_SEED", "true"); + vi.stubEnv("WEB_NEXT_SENTRY_DSN", "https://x@y/1"); + const { bindAll } = await import("./bind-production"); + const { bindSentryInstrumentation } = await import("@repo/core-shared/instrumentation"); + const { bindDevSeedBlog } = await import("@repo/blog/di/bind-dev-seed"); + + await bindAll(); + + expect(bindSentryInstrumentation).toHaveBeenCalledOnce(); + expect(bindDevSeedBlog).toHaveBeenCalledOnce(); + }); + + it("Noop instrumentation works alongside production binding (DSN unset, NODE_ENV=production)", async () => { + vi.stubEnv("WEB_NEXT_SENTRY_DSN", ""); + vi.stubEnv("NODE_ENV", "production"); + const { bindAll } = await import("./bind-production"); + const { bindNoopInstrumentation } = await import("@repo/core-shared/instrumentation"); + const { bindProductionBlog } = await import("@repo/blog/di/bind-production"); + + await bindAll(); + + expect(bindNoopInstrumentation).toHaveBeenCalledOnce(); + expect(bindProductionBlog).toHaveBeenCalledOnce(); + }); +});