285 lines
9.0 KiB
TypeScript
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 })
|
|
);
|
|
});
|
|
});
|
|
});
|