123 lines
3.0 KiB
TypeScript
123 lines
3.0 KiB
TypeScript
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);
|
|
});
|
|
});
|