import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { logger } from "../lib/logger.js"; import { dispatchWebhooks } from "../lib/webhook-dispatcher.js"; const { sendSlackNotification } = vi.hoisted(() => ({ sendSlackNotification: vi.fn(), })); vi.mock("../lib/slack-notify.js", () => ({ sendSlackNotification, })); vi.mock("../lib/logger.js", () => ({ logger: { error: vi.fn(), warn: vi.fn(), info: vi.fn(), debug: vi.fn(), }, })); describe("webhook dispatcher logging", () => { beforeEach(() => { vi.clearAllMocks(); }); afterEach(() => { vi.unstubAllGlobals(); }); it("logs dispatcher-level failures with event context", async () => { const db = { webhook: { findMany: vi.fn().mockRejectedValue(new Error("database unavailable")), }, }; dispatchWebhooks(db, "estimate.submitted", { id: "estimate_1" }); await vi.waitFor(() => { expect(logger.error).toHaveBeenCalledWith( { err: expect.any(Error), event: "estimate.submitted", }, "Failed to dispatch webhooks", ); }); }); it("logs webhook delivery failures with webhook metadata", async () => { sendSlackNotification.mockRejectedValueOnce(new Error("slack down")); const db = { webhook: { findMany: vi.fn().mockResolvedValue([ { id: "wh_1", name: "Ops Slack", url: "https://hooks.slack.com/services/test", secret: null, events: ["project.created"], }, ]), }, }; dispatchWebhooks(db, "project.created", { id: "project_1", name: "Project One" }); await vi.waitFor(() => { expect(logger.warn).toHaveBeenCalledWith( { err: expect.any(Error), event: "project.created", webhookId: "wh_1", webhookName: "Ops Slack", webhookUrl: "https://hooks.slack.com/services/test", }, "Webhook delivery failed", ); }); }); it("treats non-2xx HTTP webhook responses as delivery failures", async () => { const fetchMock = vi.fn().mockResolvedValue({ ok: false, status: 500, }); vi.stubGlobal("fetch", fetchMock); const db = { webhook: { findMany: vi.fn().mockResolvedValue([ { id: "wh_http_1", name: "Project Webhook", url: "https://example.com/webhooks/project", secret: "secret", events: ["project.created"], }, ]), }, }; dispatchWebhooks(db, "project.created", { id: "project_1", name: "Project One" }); await vi.waitFor(() => { expect(logger.warn).toHaveBeenCalledWith( { err: expect.any(Error), event: "project.created", webhookId: "wh_http_1", webhookName: "Project Webhook", webhookUrl: "https://example.com/webhooks/project", }, "Webhook delivery failed", ); }); expect(fetchMock).toHaveBeenCalledTimes(1); }); });