Files
calendar/packages/features/bookings/lib/handleNewBooking/test/webhook-producer-booking-requested.test.ts
Benny JooGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
ab21c7f805 refactor: Cal.diy (#28903)
* feat: Cal.diy — community-driven MIT-licensed fork of Cal.com

This squashed commit contains all Cal.diy changes applied on top of calcom/cal.com main:

- Rebrand Cal.com to Cal.diy across the entire codebase
- Remove Enterprise Edition (EE) features, license checks, and AGPL restrictions
- Switch license from AGPL-3.0 to MIT
- Remove docs/ directory (migrated to Nextra at cal.diy)
- Remove dead code: org tests, EE tips, platform nav, premium username, SAML/SSO, etc.
- Clean up .env.example for self-hosted Cal.diy
- Update Docker image references to calcom/cal.diy
- Update README, CONTRIBUTING.md, and issue templates for Cal.diy community fork
- Add PR welcome bot for Cal.diy contributors
- Fix API v2 breaking changes oasdiff ignore entries
- Replace Blacksmith CI runners with default GitHub Actions

3893 files changed, 20789 insertions(+), 411020 deletions(-)

Co-Authored-By: [email protected] <[email protected]>

* refactor: remove org-specific /organizations/:orgId endpoints from API v2 atoms controllers (#1701)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: revert Cal.diy Inc to Cal.com, Inc. in license files, copyright notices, and package metadata (#1702)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* rip out org related comments in api v2

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-04-15 09:52:36 -03:00

801 lines
27 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Integration tests verifying that the booking flow correctly invokes the webhook producer
* for BOOKING_REQUESTED scenarios.
*
* These tests exercise the full handleNewBooking path (event type creation → booking → webhook producer invocation)
* and assert that deps.webhookProducer.queueBookingRequestedWebhook is called (or not called) with correct params.
*
* This pattern is extendable: as more webhook triggers are migrated to the producer/consumer architecture,
* new test files can follow this same structure — mock the producer, run the booking flow, assert on the mock.
*/
import {
expectWebhookProducerCalled,
expectWebhookProducerNotCalled,
type MockWebhookProducer,
resetMockWebhookProducer,
} from "@calcom/testing/lib/webhookProducer";
const mockWebhookProducer: MockWebhookProducer = vi.hoisted(() => ({
queueBookingCreatedWebhook: vi.fn().mockResolvedValue(undefined),
queueBookingCancelledWebhook: vi.fn().mockResolvedValue(undefined),
queueBookingRescheduledWebhook: vi.fn().mockResolvedValue(undefined),
queueBookingRequestedWebhook: vi.fn().mockResolvedValue(undefined),
queueBookingRejectedWebhook: vi.fn().mockResolvedValue(undefined),
queueBookingPaymentInitiatedWebhook: vi.fn().mockResolvedValue(undefined),
queueBookingPaidWebhook: vi.fn().mockResolvedValue(undefined),
queueBookingNoShowUpdatedWebhook: vi.fn().mockResolvedValue(undefined),
queueFormSubmittedWebhook: vi.fn().mockResolvedValue(undefined),
queueRecordingReadyWebhook: vi.fn().mockResolvedValue(undefined),
queueOOOCreatedWebhook: vi.fn().mockResolvedValue(undefined),
}));
vi.mock("@calcom/features/webhooks/lib/service/WebhookTaskerProducerService", () => {
const MockProducer = class {
queueBookingCreatedWebhook = mockWebhookProducer.queueBookingCreatedWebhook;
queueBookingCancelledWebhook = mockWebhookProducer.queueBookingCancelledWebhook;
queueBookingRescheduledWebhook = mockWebhookProducer.queueBookingRescheduledWebhook;
queueBookingRequestedWebhook = mockWebhookProducer.queueBookingRequestedWebhook;
queueBookingRejectedWebhook = mockWebhookProducer.queueBookingRejectedWebhook;
queueBookingPaymentInitiatedWebhook = mockWebhookProducer.queueBookingPaymentInitiatedWebhook;
queueBookingPaidWebhook = mockWebhookProducer.queueBookingPaidWebhook;
queueBookingNoShowUpdatedWebhook = mockWebhookProducer.queueBookingNoShowUpdatedWebhook;
queueFormSubmittedWebhook = mockWebhookProducer.queueFormSubmittedWebhook;
queueRecordingReadyWebhook = mockWebhookProducer.queueRecordingReadyWebhook;
queueOOOCreatedWebhook = mockWebhookProducer.queueOOOCreatedWebhook;
};
return { WebhookTaskerProducerService: MockProducer };
});
import {
BookingLocations,
createBookingScenario,
getBooker,
getDate,
getGoogleCalendarCredential,
getMockBookingReference,
getOrganizer,
getScenarioData,
mockCalendarToHaveNoBusySlots,
mockSuccessfulVideoMeetingCreation,
TestData,
} from "@calcom/testing/lib/bookingScenario/bookingScenario";
import process from "node:process";
import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData";
import { BookingStatus, SchedulingType } from "@calcom/prisma/enums";
import {
expectBookingInDBToBeRescheduledFromTo,
expectBookingRequestedEmails,
expectBookingToBeInDatabase,
} from "@calcom/testing/lib/bookingScenario/expects";
import { getMockRequestDataForBooking } from "@calcom/testing/lib/bookingScenario/getMockRequestDataForBooking";
import { setupAndTeardown } from "@calcom/testing/lib/bookingScenario/setupAndTeardown";
import { test } from "@calcom/testing/lib/fixtures/fixtures";
import { beforeEach, describe, expect, vi } from "vitest";
import { getNewBookingHandler } from "./getNewBookingHandler";
const timeout = process.env.CI ? 5000 : 20000;
describe("Webhook Producer – BOOKING_REQUESTED", () => {
setupAndTeardown();
beforeEach(() => {
resetMockWebhookProducer(mockWebhookProducer);
});
describe("Fresh booking with confirmation required", () => {
test(
"should call queueBookingRequestedWebhook when event type requires confirmation",
async ({ emails }) => {
const handleNewBooking = getNewBookingHandler();
const booker = getBooker({
email: "[email protected]",
name: "Booker",
});
const organizer = getOrganizer({
name: "Organizer",
email: "[email protected]",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
});
await createBookingScenario(
getScenarioData({
webhooks: [
{
userId: organizer.id,
eventTriggers: ["BOOKING_CREATED"],
subscriberUrl: "http://my-webhook.example.com",
active: true,
eventTypeId: 1,
appId: null,
},
],
eventTypes: [
{
id: 1,
slotInterval: 30,
requiresConfirmation: true,
length: 30,
users: [{ id: 101 }],
},
],
organizer,
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
})
);
mockSuccessfulVideoMeetingCreation({ metadataLookupKey: "dailyvideo" });
mockCalendarToHaveNoBusySlots("googlecalendar", {});
const mockBookingData = getMockRequestDataForBooking({
data: {
eventTypeId: 1,
responses: {
email: booker.email,
name: booker.name,
location: { optionValue: "", value: BookingLocations.CalVideo },
},
},
});
const createdBooking = await handleNewBooking({ bookingData: mockBookingData });
await expectBookingToBeInDatabase({
description: "",
uid: createdBooking.uid!,
eventTypeId: mockBookingData.eventTypeId,
status: BookingStatus.PENDING,
});
expectWebhookProducerCalled(mockWebhookProducer, "queueBookingRequestedWebhook", {
bookingUid: createdBooking.uid,
eventTypeId: 1,
userId: organizer.id,
});
expectWebhookProducerNotCalled(mockWebhookProducer, "queueBookingCreatedWebhook");
expectWebhookProducerNotCalled(mockWebhookProducer, "queueBookingRescheduledWebhook");
expectBookingRequestedEmails({ booker, organizer, emails });
},
timeout
);
test(
"should call queueBookingRequestedWebhook even when booker is the organizer",
async ({ emails }) => {
const handleNewBooking = getNewBookingHandler();
const booker = getBooker({
email: "[email protected]",
name: "Booker",
});
const organizer = getOrganizer({
name: "Organizer",
email: "[email protected]",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
});
await createBookingScenario(
getScenarioData({
webhooks: [
{
userId: organizer.id,
eventTriggers: ["BOOKING_CREATED"],
subscriberUrl: "http://my-webhook.example.com",
active: true,
eventTypeId: 1,
appId: null,
},
],
eventTypes: [
{
id: 1,
slotInterval: 30,
requiresConfirmation: true,
length: 30,
users: [{ id: 101 }],
},
],
organizer,
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
})
);
mockSuccessfulVideoMeetingCreation({ metadataLookupKey: "dailyvideo" });
mockCalendarToHaveNoBusySlots("googlecalendar", {});
const mockBookingData = getMockRequestDataForBooking({
data: {
eventTypeId: 1,
responses: {
email: booker.email,
name: booker.name,
location: { optionValue: "", value: BookingLocations.CalVideo },
},
},
});
const createdBooking = await handleNewBooking({
bookingData: mockBookingData,
userId: organizer.id,
});
await expectBookingToBeInDatabase({
description: "",
uid: createdBooking.uid!,
eventTypeId: mockBookingData.eventTypeId,
status: BookingStatus.PENDING,
});
expectWebhookProducerCalled(mockWebhookProducer, "queueBookingRequestedWebhook", {
bookingUid: createdBooking.uid,
eventTypeId: 1,
userId: organizer.id,
});
expectBookingRequestedEmails({ booker, organizer, emails });
},
timeout
);
});
describe("Confirmation threshold", () => {
test(
"should NOT call queueBookingRequestedWebhook when confirmation threshold is not met",
async () => {
const handleNewBooking = getNewBookingHandler();
const booker = getBooker({
email: "[email protected]",
name: "Booker",
});
const organizer = getOrganizer({
name: "Organizer",
email: "[email protected]",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
});
await createBookingScenario(
getScenarioData({
webhooks: [
{
userId: organizer.id,
eventTriggers: ["BOOKING_CREATED"],
subscriberUrl: "http://my-webhook.example.com",
active: true,
eventTypeId: 1,
appId: null,
},
],
eventTypes: [
{
id: 1,
slotInterval: 30,
requiresConfirmation: true,
metadata: {
requiresConfirmationThreshold: {
time: 30,
unit: "minutes",
},
},
length: 30,
users: [{ id: 101 }],
},
],
organizer,
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
})
);
mockSuccessfulVideoMeetingCreation({ metadataLookupKey: "dailyvideo" });
mockCalendarToHaveNoBusySlots("googlecalendar", {});
const mockBookingData = getMockRequestDataForBooking({
data: {
eventTypeId: 1,
responses: {
email: booker.email,
name: booker.name,
location: { optionValue: "", value: BookingLocations.CalVideo },
},
},
});
const createdBooking = await handleNewBooking({ bookingData: mockBookingData });
await expectBookingToBeInDatabase({
description: "",
uid: createdBooking.uid!,
eventTypeId: mockBookingData.eventTypeId,
status: BookingStatus.ACCEPTED,
});
expectWebhookProducerNotCalled(mockWebhookProducer, "queueBookingRequestedWebhook");
},
timeout
);
test(
"should call queueBookingRequestedWebhook when confirmation threshold IS met",
async ({ emails }) => {
const handleNewBooking = getNewBookingHandler();
const booker = getBooker({
email: "[email protected]",
name: "Booker",
});
const organizer = getOrganizer({
name: "Organizer",
email: "[email protected]",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
});
const { dateString: plus3DateString } = getDate({ dateIncrement: 3 });
await createBookingScenario(
getScenarioData({
webhooks: [
{
userId: organizer.id,
eventTriggers: ["BOOKING_CREATED"],
subscriberUrl: "http://my-webhook.example.com",
active: true,
eventTypeId: 1,
appId: null,
},
],
eventTypes: [
{
id: 1,
slotInterval: 30,
requiresConfirmation: true,
metadata: {
requiresConfirmationThreshold: {
time: 120,
unit: "hours",
},
},
length: 30,
users: [{ id: 101 }],
},
],
organizer,
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
})
);
mockSuccessfulVideoMeetingCreation({ metadataLookupKey: "dailyvideo" });
mockCalendarToHaveNoBusySlots("googlecalendar", {});
const mockBookingData = getMockRequestDataForBooking({
data: {
eventTypeId: 1,
start: `${plus3DateString}T05:00:00.000Z`,
end: `${plus3DateString}T05:30:00.000Z`,
responses: {
email: booker.email,
name: booker.name,
location: { optionValue: "", value: BookingLocations.CalVideo },
},
},
});
const createdBooking = await handleNewBooking({ bookingData: mockBookingData });
await expectBookingToBeInDatabase({
description: "",
uid: createdBooking.uid!,
eventTypeId: mockBookingData.eventTypeId,
status: BookingStatus.PENDING,
});
expectWebhookProducerCalled(mockWebhookProducer, "queueBookingRequestedWebhook", {
bookingUid: createdBooking.uid,
eventTypeId: 1,
userId: organizer.id,
});
expectBookingRequestedEmails({ booker, organizer, emails });
},
timeout
);
});
// "Paid event with confirmation required" tests removed — handleStripePaymentSuccess was part of EE payments (removed)
describe("Reschedule with confirmation required", () => {
test(
"should call queueBookingRequestedWebhook when non-organizer reschedules a booking requiring confirmation",
async ({ emails }) => {
const handleNewBooking = getNewBookingHandler();
const booker = getBooker({
email: "[email protected]",
name: "Booker",
});
const organizer = getOrganizer({
name: "Organizer",
email: "[email protected]",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
});
const { dateString: plus1DateString } = getDate({ dateIncrement: 1 });
const uidOfBookingToBeRescheduled = "n5Wv3eHgconAED2j4gcVhP";
await createBookingScenario(
getScenarioData({
webhooks: [
{
userId: organizer.id,
eventTriggers: ["BOOKING_CREATED"],
subscriberUrl: "http://my-webhook.example.com",
active: true,
eventTypeId: 1,
appId: null,
},
],
eventTypes: [
{
id: 1,
slotInterval: 15,
requiresConfirmation: true,
length: 15,
users: [{ id: 101 }],
},
],
bookings: [
{
uid: uidOfBookingToBeRescheduled,
eventTypeId: 1,
status: BookingStatus.ACCEPTED,
startTime: `${plus1DateString}T05:00:00.000Z`,
endTime: `${plus1DateString}T05:15:00.000Z`,
references: [
getMockBookingReference({
type: appStoreMetadata.dailyvideo.type,
uid: "MOCK_ID",
meetingId: "MOCK_ID",
meetingPassword: "MOCK_PASS",
meetingUrl: "http://mock-dailyvideo.example.com",
credentialId: 0,
}),
getMockBookingReference({
type: appStoreMetadata.googlecalendar.type,
uid: "MOCK_ID",
meetingId: "MOCK_ID",
meetingPassword: "MOCK_PASSWORD",
meetingUrl: "https://UNUSED_URL",
externalCalendarId: "MOCK_EXTERNAL_CALENDAR_ID",
credentialId: 1,
}),
],
},
],
organizer,
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
})
);
mockSuccessfulVideoMeetingCreation({ metadataLookupKey: "dailyvideo" });
mockCalendarToHaveNoBusySlots("googlecalendar", {
create: { uid: "MOCK_ID" },
update: { uid: "UPDATED_MOCK_ID", iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID" },
});
const mockBookingData = getMockRequestDataForBooking({
data: {
eventTypeId: 1,
rescheduleUid: uidOfBookingToBeRescheduled,
start: `${plus1DateString}T04:00:00.000Z`,
end: `${plus1DateString}T04:15:00.000Z`,
responses: {
email: booker.email,
name: booker.name,
location: { optionValue: "", value: BookingLocations.CalVideo },
},
},
});
const createdBooking = await handleNewBooking({ bookingData: mockBookingData });
await expectBookingInDBToBeRescheduledFromTo({
from: { uid: uidOfBookingToBeRescheduled },
to: {
description: "",
uid: createdBooking.uid!,
eventTypeId: mockBookingData.eventTypeId,
status: BookingStatus.PENDING,
location: BookingLocations.CalVideo,
responses: expect.objectContaining({
email: booker.email,
name: booker.name,
}),
},
});
expectWebhookProducerCalled(mockWebhookProducer, "queueBookingRequestedWebhook", {
bookingUid: createdBooking.uid,
eventTypeId: 1,
userId: organizer.id,
});
expectWebhookProducerNotCalled(mockWebhookProducer, "queueBookingRescheduledWebhook");
expectBookingRequestedEmails({ booker, organizer, emails });
},
timeout
);
test(
"should NOT call queueBookingRequestedWebhook when organizer reschedules their own booking requiring confirmation",
async () => {
const handleNewBooking = getNewBookingHandler();
const booker = getBooker({
email: "[email protected]",
name: "Booker",
});
const organizer = getOrganizer({
name: "Organizer",
email: "[email protected]",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
});
const { dateString: plus1DateString } = getDate({ dateIncrement: 1 });
const uidOfBookingToBeRescheduled = "n5Wv3eHgconAED2j4gcVhP";
await createBookingScenario(
getScenarioData({
webhooks: [
{
userId: organizer.id,
eventTriggers: ["BOOKING_CREATED"],
subscriberUrl: "http://my-webhook.example.com",
active: true,
eventTypeId: 1,
appId: null,
},
],
eventTypes: [
{
id: 1,
requiresConfirmation: true,
slotInterval: 15,
length: 15,
users: [{ id: 101 }],
destinationCalendar: {
integration: "google_calendar",
externalId: "[email protected]",
},
},
],
bookings: [
{
uid: uidOfBookingToBeRescheduled,
eventTypeId: 1,
userId: organizer.id,
status: BookingStatus.ACCEPTED,
startTime: `${plus1DateString}T05:00:00.000Z`,
endTime: `${plus1DateString}T05:15:00.000Z`,
references: [
getMockBookingReference({
type: appStoreMetadata.dailyvideo.type,
uid: "MOCK_ID",
meetingId: "MOCK_ID",
meetingPassword: "MOCK_PASS",
meetingUrl: "http://mock-dailyvideo.example.com",
credentialId: 0,
}),
getMockBookingReference({
type: appStoreMetadata.googlecalendar.type,
uid: "MOCK_ID",
meetingId: "MOCK_ID",
meetingPassword: "MOCK_PASSWORD",
meetingUrl: "https://UNUSED_URL",
externalCalendarId: "MOCK_EXTERNAL_CALENDAR_ID",
credentialId: 1,
}),
],
},
],
organizer,
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
})
);
mockSuccessfulVideoMeetingCreation({ metadataLookupKey: "dailyvideo" });
mockCalendarToHaveNoBusySlots("googlecalendar", {
create: { uid: "MOCK_ID" },
update: { uid: "UPDATED_MOCK_ID", iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID" },
});
const mockBookingData = getMockRequestDataForBooking({
data: {
eventTypeId: 1,
rescheduleUid: uidOfBookingToBeRescheduled,
start: `${plus1DateString}T04:00:00.000Z`,
end: `${plus1DateString}T04:15:00.000Z`,
responses: {
email: booker.email,
name: booker.name,
location: { optionValue: "", value: BookingLocations.CalVideo },
},
},
});
const createdBooking = await handleNewBooking({
bookingData: mockBookingData,
userId: organizer.id,
});
await expectBookingToBeInDatabase({
description: "",
uid: createdBooking.uid!,
eventTypeId: mockBookingData.eventTypeId,
status: BookingStatus.ACCEPTED,
});
expectWebhookProducerNotCalled(mockWebhookProducer, "queueBookingRequestedWebhook");
},
timeout
);
});
describe("Collective scheduling with confirmation required", () => {
test(
"should call queueBookingRequestedWebhook for collective team booking requiring confirmation",
async ({ emails }) => {
const handleNewBooking = getNewBookingHandler();
const booker = getBooker({
email: "[email protected]",
name: "Booker",
});
const otherTeamMembers = [
{
name: "Other Team Member 1",
username: "other-team-member-1",
timeZone: "Asia/Kolkata",
defaultScheduleId: null,
email: "[email protected]",
id: 102,
schedules: [TestData.schedules.IstEveningShift],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
destinationCalendar: {
integration: TestData.apps["google-calendar"].type,
externalId: "[email protected]",
},
},
];
const organizer = getOrganizer({
name: "Organizer",
email: "[email protected]",
id: 101,
defaultScheduleId: null,
schedules: [TestData.schedules.IstMorningShift],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
destinationCalendar: {
integration: TestData.apps["google-calendar"].type,
externalId: "[email protected]",
},
teams: [
{
membership: { accepted: true },
team: {
id: 1,
name: "Team 1",
slug: "team-1",
},
},
],
});
await createBookingScenario(
getScenarioData({
webhooks: [
{
userId: organizer.id,
eventTriggers: ["BOOKING_CREATED"],
subscriberUrl: "http://my-webhook.example.com",
active: true,
eventTypeId: 1,
appId: null,
},
],
eventTypes: [
{
id: 1,
teamId: 1,
slotInterval: 15,
requiresConfirmation: true,
schedulingType: SchedulingType.COLLECTIVE,
length: 15,
users: [{ id: 101 }, { id: 102 }],
schedule: TestData.schedules.IstMorningShift,
destinationCalendar: {
integration: TestData.apps["google-calendar"].type,
externalId: "[email protected]",
},
},
],
organizer,
usersApartFromOrganizer: otherTeamMembers,
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
})
);
mockSuccessfulVideoMeetingCreation({
metadataLookupKey: appStoreMetadata.dailyvideo.dirName,
videoMeetingData: {
id: "MOCK_ID",
password: "MOCK_PASS",
url: `http://mock-dailyvideo.example.com/meeting-1`,
},
});
mockCalendarToHaveNoBusySlots("googlecalendar", {
create: {
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
},
});
const mockBookingData = getMockRequestDataForBooking({
data: {
start: `${getDate({ dateIncrement: 1 }).dateString}T11:30:00.000Z`,
end: `${getDate({ dateIncrement: 1 }).dateString}T11:45:00.000Z`,
eventTypeId: 1,
responses: {
email: booker.email,
name: booker.name,
location: { optionValue: "", value: BookingLocations.CalVideo },
},
},
});
const createdBooking = await handleNewBooking({ bookingData: mockBookingData });
await expectBookingToBeInDatabase({
description: "",
uid: createdBooking.uid!,
eventTypeId: mockBookingData.eventTypeId,
status: BookingStatus.PENDING,
});
expectWebhookProducerCalled(mockWebhookProducer, "queueBookingRequestedWebhook", {
bookingUid: createdBooking.uid,
eventTypeId: 1,
userId: organizer.id,
});
expectWebhookProducerNotCalled(mockWebhookProducer, "queueBookingCreatedWebhook");
expectBookingRequestedEmails({ organizer, emails });
},
timeout
);
});
});