Files
calendar/packages/features/webhooks/lib/service/__tests__/WebhookTaskerProducerService.test.ts
T
2026-01-22 16:11:10 -03:00

285 lines
9.0 KiB
TypeScript

import { WebhookTriggerEvents } from "@calcom/prisma/enums";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { ITasker } from "../../interface";
import type { ILogger } from "../../interface/infrastructure";
import { WebhookTaskerProducerService } from "../WebhookTaskerProducerService";
/**
* Unit Tests for WebhookTaskerProducerService
*
* Tests the lightweight Producer service for queueing webhook delivery tasks.
*/
describe("WebhookTaskerProducerService", () => {
let producer: WebhookTaskerProducerService;
let mockTasker: ITasker;
let mockLogger: ILogger;
beforeEach(() => {
// Mock Tasker
mockTasker = {
create: vi.fn().mockResolvedValue("task-id-123"),
cleanup: vi.fn().mockResolvedValue(undefined),
cancel: vi.fn().mockResolvedValue("cancelled-task-id"),
cancelWithReference: vi.fn().mockResolvedValue("cancelled-ref-id"),
};
// Mock Logger
mockLogger = {
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
getSubLogger: vi.fn().mockReturnThis(),
} as unknown as ILogger;
producer = new WebhookTaskerProducerService(mockTasker, mockLogger);
});
describe("Constructor & Dependencies", () => {
it("should be instantiable with Tasker and Logger", () => {
expect(producer).toBeInstanceOf(WebhookTaskerProducerService);
});
it("should create sub-logger with prefix", () => {
expect(mockLogger.getSubLogger).toHaveBeenCalledWith({
prefix: ["[WebhookTaskerProducerService]"],
});
});
});
describe("queueBookingCreatedWebhook", () => {
it("should queue a BOOKING_CREATED webhook task", async () => {
await producer.queueBookingCreatedWebhook({
triggerEvent: WebhookTriggerEvents.BOOKING_CREATED,
bookingUid: "booking-123",
eventTypeId: 456,
userId: 789,
});
expect(mockTasker.create).toHaveBeenCalledWith(
"webhookDelivery",
expect.objectContaining({
triggerEvent: WebhookTriggerEvents.BOOKING_CREATED,
bookingUid: "booking-123",
eventTypeId: 456,
userId: 789,
operationId: expect.any(String),
timestamp: expect.any(String),
})
);
});
it("should generate operationId if not provided", async () => {
await producer.queueBookingCreatedWebhook({
triggerEvent: WebhookTriggerEvents.BOOKING_CREATED,
bookingUid: "booking-123",
});
const callArgs = vi.mocked(mockTasker.create).mock.calls[0];
const payload = callArgs[1];
expect(payload).toHaveProperty("operationId");
expect(payload.operationId).toMatch(/^[0-9a-f-]{36}$/); // UUID format
});
it("should use provided operationId", async () => {
await producer.queueBookingCreatedWebhook({
triggerEvent: WebhookTriggerEvents.BOOKING_CREATED,
bookingUid: "booking-123",
operationId: "custom-op-id",
});
const callArgs = vi.mocked(mockTasker.create).mock.calls[0];
const payload = callArgs[1];
expect(payload.operationId).toBe("custom-op-id");
});
it("should log debug messages", async () => {
await producer.queueBookingCreatedWebhook({
bookingUid: "booking-123",
});
expect(mockLogger.debug).toHaveBeenCalledWith(
"Queueing booking webhook task",
expect.objectContaining({
operationId: expect.any(String),
triggerEvent: WebhookTriggerEvents.BOOKING_CREATED,
bookingUid: "booking-123",
})
);
expect(mockLogger.debug).toHaveBeenCalledWith(
"Webhook delivery task queued",
expect.objectContaining({
operationId: expect.any(String),
})
);
});
});
describe("queueBookingCancelledWebhook", () => {
it("should queue a BOOKING_CANCELLED webhook task", async () => {
await producer.queueBookingCancelledWebhook({
bookingUid: "booking-456",
});
expect(mockTasker.create).toHaveBeenCalledWith(
"webhookDelivery",
expect.objectContaining({
triggerEvent: WebhookTriggerEvents.BOOKING_CANCELLED,
bookingUid: "booking-456",
})
);
});
});
describe("Metadata Support", () => {
it("should include metadata if provided", async () => {
await producer.queueBookingCreatedWebhook({
bookingUid: "booking-123",
metadata: { customField: "value" },
});
const callArgs = vi.mocked(mockTasker.create).mock.calls[0];
const payload = callArgs[1];
expect(payload.metadata).toEqual({ customField: "value" });
});
});
describe("Error Handling", () => {
it("should log and rethrow error if Tasker fails", async () => {
const error = new Error("Tasker failed");
vi.mocked(mockTasker.create).mockRejectedValueOnce(error);
await expect(
producer.queueBookingCreatedWebhook({
bookingUid: "booking-123",
})
).rejects.toThrow("Tasker failed");
expect(mockLogger.error).toHaveBeenCalledWith(
"Failed to queue webhook delivery task",
expect.objectContaining({
error: "Tasker failed",
})
);
});
});
describe("All Event-Specific Methods", () => {
it("should have queueBookingCreatedWebhook", async () => {
await producer.queueBookingCreatedWebhook({
bookingUid: "test-123",
});
expect(mockTasker.create).toHaveBeenCalledWith(
"webhookDelivery",
expect.objectContaining({ triggerEvent: WebhookTriggerEvents.BOOKING_CREATED })
);
});
it("should have queueBookingCancelledWebhook", async () => {
await producer.queueBookingCancelledWebhook({
bookingUid: "test-123",
});
expect(mockTasker.create).toHaveBeenCalledWith(
"webhookDelivery",
expect.objectContaining({ triggerEvent: WebhookTriggerEvents.BOOKING_CANCELLED })
);
});
it("should have queueBookingRescheduledWebhook", async () => {
await producer.queueBookingRescheduledWebhook({
bookingUid: "test-123",
});
expect(mockTasker.create).toHaveBeenCalledWith(
"webhookDelivery",
expect.objectContaining({ triggerEvent: WebhookTriggerEvents.BOOKING_RESCHEDULED })
);
});
it("should have queueBookingRequestedWebhook", async () => {
await producer.queueBookingRequestedWebhook({
bookingUid: "test-123",
});
expect(mockTasker.create).toHaveBeenCalledWith(
"webhookDelivery",
expect.objectContaining({ triggerEvent: WebhookTriggerEvents.BOOKING_REQUESTED })
);
});
it("should have queueBookingRejectedWebhook", async () => {
await producer.queueBookingRejectedWebhook({
bookingUid: "test-123",
});
expect(mockTasker.create).toHaveBeenCalledWith(
"webhookDelivery",
expect.objectContaining({ triggerEvent: WebhookTriggerEvents.BOOKING_REJECTED })
);
});
it("should have queueBookingPaymentInitiatedWebhook", async () => {
await producer.queueBookingPaymentInitiatedWebhook({
bookingUid: "test-123",
});
expect(mockTasker.create).toHaveBeenCalledWith(
"webhookDelivery",
expect.objectContaining({ triggerEvent: WebhookTriggerEvents.BOOKING_PAYMENT_INITIATED })
);
});
it("should have queueBookingPaidWebhook", async () => {
await producer.queueBookingPaidWebhook({
bookingUid: "test-123",
});
expect(mockTasker.create).toHaveBeenCalledWith(
"webhookDelivery",
expect.objectContaining({ triggerEvent: WebhookTriggerEvents.BOOKING_PAID })
);
});
it("should have queueBookingNoShowUpdatedWebhook", async () => {
await producer.queueBookingNoShowUpdatedWebhook({
bookingUid: "test-123",
});
expect(mockTasker.create).toHaveBeenCalledWith(
"webhookDelivery",
expect.objectContaining({ triggerEvent: WebhookTriggerEvents.BOOKING_NO_SHOW_UPDATED })
);
});
it("should have queueFormSubmittedWebhook", async () => {
await producer.queueFormSubmittedWebhook({
formId: "form-123",
});
expect(mockTasker.create).toHaveBeenCalledWith(
"webhookDelivery",
expect.objectContaining({ triggerEvent: WebhookTriggerEvents.FORM_SUBMITTED })
);
});
it("should have queueRecordingReadyWebhook", async () => {
await producer.queueRecordingReadyWebhook({
recordingId: "rec-123",
bookingUid: "booking-123",
});
expect(mockTasker.create).toHaveBeenCalledWith(
"webhookDelivery",
expect.objectContaining({ triggerEvent: WebhookTriggerEvents.RECORDING_READY })
);
});
it("should have queueOOOCreatedWebhook", async () => {
await producer.queueOOOCreatedWebhook({
oooEntryId: 123,
userId: 456,
});
expect(mockTasker.create).toHaveBeenCalledWith(
"webhookDelivery",
expect.objectContaining({ triggerEvent: WebhookTriggerEvents.OOO_CREATED })
);
});
});
});