More tests
parent
3fe6d8b781
commit
82bea948ea
|
@ -19,7 +19,7 @@ declare global {
|
||||||
|
|
||||||
expect.extend({
|
expect.extend({
|
||||||
toHaveEmail(
|
toHaveEmail(
|
||||||
testEmails: ReturnType<Fixtures["emails"]["get"]>,
|
emails: Fixtures["emails"],
|
||||||
expectedEmail: {
|
expectedEmail: {
|
||||||
//TODO: Support email HTML parsing to target specific elements
|
//TODO: Support email HTML parsing to target specific elements
|
||||||
htmlToContain?: string;
|
htmlToContain?: string;
|
||||||
|
@ -27,7 +27,7 @@ expect.extend({
|
||||||
},
|
},
|
||||||
to: string
|
to: string
|
||||||
) {
|
) {
|
||||||
const testEmail = testEmails.find((email) => email.to === to);
|
const testEmail = emails.get().find((email) => email.to.includes(to));
|
||||||
if (!testEmail) {
|
if (!testEmail) {
|
||||||
return {
|
return {
|
||||||
pass: false,
|
pass: false,
|
||||||
|
@ -111,3 +111,124 @@ export function expectBookingToBeInDatabase(booking: Partial<Booking> & Pick<Boo
|
||||||
});
|
});
|
||||||
expect(actualBooking).toEqual(expect.objectContaining(booking));
|
expect(actualBooking).toEqual(expect.objectContaining(booking));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function expectSuccessfulBookingCreationEmails({
|
||||||
|
emails,
|
||||||
|
organizer,
|
||||||
|
booker,
|
||||||
|
}: {
|
||||||
|
emails: Fixtures["emails"];
|
||||||
|
organizer: { email: string; name: string };
|
||||||
|
booker: { email: string; name: string };
|
||||||
|
}) {
|
||||||
|
expect(emails).toHaveEmail(
|
||||||
|
{
|
||||||
|
htmlToContain: "<title>confirmed_event_type_subject</title>",
|
||||||
|
to: `${organizer.email}`,
|
||||||
|
},
|
||||||
|
`${organizer.email}`
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(emails).toHaveEmail(
|
||||||
|
{
|
||||||
|
htmlToContain: "<title>confirmed_event_type_subject</title>",
|
||||||
|
to: `${booker.name} <${booker.email}>`,
|
||||||
|
},
|
||||||
|
`${booker.name} <${booker.email}>`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expectAwaitingPaymentEmails({
|
||||||
|
emails,
|
||||||
|
organizer,
|
||||||
|
booker,
|
||||||
|
}: {
|
||||||
|
emails: Fixtures["emails"];
|
||||||
|
organizer: { email: string; name: string };
|
||||||
|
booker: { email: string; name: string };
|
||||||
|
}) {
|
||||||
|
expect(emails).toHaveEmail(
|
||||||
|
{
|
||||||
|
htmlToContain: "<title>awaiting_payment_subject</title>",
|
||||||
|
to: `${booker.name} <${booker.email}>`,
|
||||||
|
},
|
||||||
|
`${booker.email}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expectBookingRequestedEmails({
|
||||||
|
emails,
|
||||||
|
organizer,
|
||||||
|
booker,
|
||||||
|
}: {
|
||||||
|
emails: Fixtures["emails"];
|
||||||
|
organizer: { email: string; name: string };
|
||||||
|
booker: { email: string; name: string };
|
||||||
|
}) {
|
||||||
|
expect(emails).toHaveEmail(
|
||||||
|
{
|
||||||
|
htmlToContain: "<title>event_awaiting_approval_subject</title>",
|
||||||
|
to: `${organizer.email}`,
|
||||||
|
},
|
||||||
|
`${organizer.email}`
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(emails).toHaveEmail(
|
||||||
|
{
|
||||||
|
htmlToContain: "<title>booking_submitted_subject</title>",
|
||||||
|
to: `${booker.email}`,
|
||||||
|
},
|
||||||
|
`${booker.email}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expectBookingRequestedWebhookToHaveBeenFired({
|
||||||
|
organizer,
|
||||||
|
booker,
|
||||||
|
location,
|
||||||
|
subscriberUrl,
|
||||||
|
paidEvent,
|
||||||
|
}: {
|
||||||
|
organizer: { email: string; name: string };
|
||||||
|
booker: { email: string; name: string };
|
||||||
|
subscriberUrl: string;
|
||||||
|
location: string;
|
||||||
|
paidEvent?: boolean;
|
||||||
|
}) {
|
||||||
|
// There is an inconsistency in the way we send the data to the webhook for paid events and unpaid events. Fix that and then remove this if statement.
|
||||||
|
if (!paidEvent) {
|
||||||
|
expectWebhookToHaveBeenCalledWith(subscriberUrl, {
|
||||||
|
triggerEvent: "BOOKING_REQUESTED",
|
||||||
|
payload: {
|
||||||
|
metadata: {
|
||||||
|
// In a Pending Booking Request, we don't send the video call url
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
name: { label: "your_name", value: booker.name },
|
||||||
|
email: { label: "email_address", value: booker.email },
|
||||||
|
location: {
|
||||||
|
label: "location",
|
||||||
|
value: { optionValue: "", value: location },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
expectWebhookToHaveBeenCalledWith(subscriberUrl, {
|
||||||
|
triggerEvent: "BOOKING_REQUESTED",
|
||||||
|
payload: {
|
||||||
|
metadata: {
|
||||||
|
// In a Pending Booking Request, we don't send the video call url
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
name: { label: "name", value: booker.name },
|
||||||
|
email: { label: "email", value: booker.email },
|
||||||
|
location: {
|
||||||
|
label: "location",
|
||||||
|
value: { optionValue: "", value: location },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -31,17 +31,20 @@ import {
|
||||||
|
|
||||||
import {
|
import {
|
||||||
expectWorkflowToBeTriggered,
|
expectWorkflowToBeTriggered,
|
||||||
|
expectSuccessfulBookingCreationEmails,
|
||||||
expectBookingToBeInDatabase,
|
expectBookingToBeInDatabase,
|
||||||
expectWebhookToHaveBeenCalledWith,
|
expectWebhookToHaveBeenCalledWith,
|
||||||
|
expectAwaitingPaymentEmails,
|
||||||
|
expectBookingRequestedEmails,
|
||||||
|
expectBookingRequestedWebhookToHaveBeenFired,
|
||||||
} from "@calcom/web/test/utils/bookingScenario/expects";
|
} from "@calcom/web/test/utils/bookingScenario/expects";
|
||||||
|
|
||||||
|
|
||||||
type CustomNextApiRequest = NextApiRequest & Request;
|
type CustomNextApiRequest = NextApiRequest & Request;
|
||||||
|
|
||||||
type CustomNextApiResponse = NextApiResponse & Response;
|
type CustomNextApiResponse = NextApiResponse & Response;
|
||||||
// Local test runs sometime gets too slow
|
// Local test runs sometime gets too slow
|
||||||
const timeout = process.env.CI ? 5000 : 20000;
|
const timeout = process.env.CI ? 5000 : 20000;
|
||||||
describe.sequential("handleNewBooking", () => {
|
describe("handleNewBooking", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Required to able to generate token in email in some cases
|
// Required to able to generate token in email in some cases
|
||||||
process.env.CALENDSO_ENCRYPTION_KEY = "abcdefghjnmkljhjklmnhjklkmnbhjui";
|
process.env.CALENDSO_ENCRYPTION_KEY = "abcdefghjnmkljhjklmnhjklkmnbhjui";
|
||||||
|
@ -52,12 +55,12 @@ describe.sequential("handleNewBooking", () => {
|
||||||
fetchMock.resetMocks();
|
fetchMock.resetMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe.sequential("Frontend:", () => {
|
describe("Frontend:", () => {
|
||||||
test(
|
test(
|
||||||
`should create a successful booking with Cal Video(Daily Video) if no explicit location is provided
|
`should create a successful booking with Cal Video(Daily Video) if no explicit location is provided
|
||||||
1. Should create a booking in the database
|
1. Should create a booking in the database
|
||||||
2. Should send emails to the booker as well as organizer
|
2. Should send emails to the booker as well as organizer
|
||||||
3. Should trigger BOOKING_CREATED webhook
|
3. Should trigger BOOKING_CREATED webhook
|
||||||
`,
|
`,
|
||||||
async ({ emails }) => {
|
async ({ emails }) => {
|
||||||
const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default;
|
const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default;
|
||||||
|
@ -75,23 +78,7 @@ describe.sequential("handleNewBooking", () => {
|
||||||
selectedCalendars: [TestData.selectedCalendars.google],
|
selectedCalendars: [TestData.selectedCalendars.google],
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockBookingData = getMockRequestDataForBooking({
|
createBookingScenario(getScenarioData({
|
||||||
data: {
|
|
||||||
eventTypeId: 1,
|
|
||||||
responses: {
|
|
||||||
email: booker.email,
|
|
||||||
name: booker.name,
|
|
||||||
location: { optionValue: "", value: "integrations:daily" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const { req } = createMockNextJsRequest({
|
|
||||||
method: "POST",
|
|
||||||
body: mockBookingData,
|
|
||||||
});
|
|
||||||
|
|
||||||
const scenarioData = getScenarioData({
|
|
||||||
webhooks: [
|
webhooks: [
|
||||||
{
|
{
|
||||||
userId: organizer.id,
|
userId: organizer.id,
|
||||||
|
@ -116,14 +103,29 @@ describe.sequential("handleNewBooking", () => {
|
||||||
],
|
],
|
||||||
organizer,
|
organizer,
|
||||||
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
|
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
|
||||||
});
|
}));
|
||||||
|
|
||||||
mockSuccessfulVideoMeetingCreation({
|
mockSuccessfulVideoMeetingCreation({
|
||||||
metadataLookupKey: "dailyvideo",
|
metadataLookupKey: "dailyvideo",
|
||||||
});
|
});
|
||||||
|
|
||||||
mockCalendarToHaveNoBusySlots("googlecalendar");
|
mockCalendarToHaveNoBusySlots("googlecalendar");
|
||||||
createBookingScenario(scenarioData);
|
|
||||||
|
const mockBookingData = getMockRequestDataForBooking({
|
||||||
|
data: {
|
||||||
|
eventTypeId: 1,
|
||||||
|
responses: {
|
||||||
|
email: booker.email,
|
||||||
|
name: booker.name,
|
||||||
|
location: { optionValue: "", value: "integrations:daily" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { req } = createMockNextJsRequest({
|
||||||
|
method: "POST",
|
||||||
|
body: mockBookingData,
|
||||||
|
});
|
||||||
|
|
||||||
const createdBooking = await handleNewBooking(req);
|
const createdBooking = await handleNewBooking(req);
|
||||||
expect(createdBooking.responses).toContain({
|
expect(createdBooking.responses).toContain({
|
||||||
|
@ -145,15 +147,8 @@ describe.sequential("handleNewBooking", () => {
|
||||||
|
|
||||||
expectWorkflowToBeTriggered();
|
expectWorkflowToBeTriggered();
|
||||||
|
|
||||||
const testEmails = emails.get();
|
expectSuccessfulBookingCreationEmails({booker, organizer, emails})
|
||||||
expect(testEmails).toHaveEmail({
|
|
||||||
htmlToContain: "<title>confirmed_event_type_subject</title>",
|
|
||||||
to: `${organizer.email}`,
|
|
||||||
}, `${organizer.email}`);
|
|
||||||
expect(testEmails).toHaveEmail({
|
|
||||||
htmlToContain: "<title>confirmed_event_type_subject</title>",
|
|
||||||
to: `${booker.name} <${booker.email}>`,
|
|
||||||
}, `${booker.name} <${booker.email}>`);
|
|
||||||
expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", {
|
expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", {
|
||||||
triggerEvent: "BOOKING_CREATED",
|
triggerEvent: "BOOKING_CREATED",
|
||||||
payload: {
|
payload: {
|
||||||
|
@ -174,14 +169,17 @@ describe.sequential("handleNewBooking", () => {
|
||||||
timeout
|
timeout
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
describe('Event Type that requires confirmation', () => {
|
||||||
test(
|
test(
|
||||||
`should submit a booking request for event requiring confirmation
|
`should create a booking request for event that requires confirmation
|
||||||
1. Should create a booking in the database with status PENDING
|
1. Should create a booking in the database with status PENDING
|
||||||
2. Should send emails to the booker as well as organizer for booking request and awaiting approval
|
2. Should send emails to the booker as well as organizer for booking request and awaiting approval
|
||||||
3. Should trigger BOOKING_REQUESTED webhook
|
3. Should trigger BOOKING_REQUESTED webhook
|
||||||
`,
|
`,
|
||||||
async ({ emails }) => {
|
async ({ emails }) => {
|
||||||
const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default;
|
const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default;
|
||||||
|
const subscriberUrl = "http://my-webhook.example.com"
|
||||||
const booker = getBooker({
|
const booker = getBooker({
|
||||||
email: "booker@example.com",
|
email: "booker@example.com",
|
||||||
name: "Booker",
|
name: "Booker",
|
||||||
|
@ -196,28 +194,12 @@ describe.sequential("handleNewBooking", () => {
|
||||||
selectedCalendars: [TestData.selectedCalendars.google],
|
selectedCalendars: [TestData.selectedCalendars.google],
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockBookingData = getMockRequestDataForBooking({
|
createBookingScenario(getScenarioData({
|
||||||
data: {
|
|
||||||
eventTypeId: 1,
|
|
||||||
responses: {
|
|
||||||
email: booker.email,
|
|
||||||
name: booker.name,
|
|
||||||
location: { optionValue: "", value: "integrations:daily" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const { req } = createMockNextJsRequest({
|
|
||||||
method: "POST",
|
|
||||||
body: mockBookingData,
|
|
||||||
});
|
|
||||||
|
|
||||||
const scenarioData = getScenarioData({
|
|
||||||
webhooks: [
|
webhooks: [
|
||||||
{
|
{
|
||||||
userId: organizer.id,
|
userId: organizer.id,
|
||||||
eventTriggers: ["BOOKING_CREATED"],
|
eventTriggers: ["BOOKING_CREATED"],
|
||||||
subscriberUrl: "http://my-webhook.example.com",
|
subscriberUrl ,
|
||||||
active: true,
|
active: true,
|
||||||
eventTypeId: 1,
|
eventTypeId: 1,
|
||||||
appId: null,
|
appId: null,
|
||||||
|
@ -238,14 +220,29 @@ describe.sequential("handleNewBooking", () => {
|
||||||
],
|
],
|
||||||
organizer,
|
organizer,
|
||||||
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
|
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
|
||||||
});
|
}));
|
||||||
|
|
||||||
mockSuccessfulVideoMeetingCreation({
|
mockSuccessfulVideoMeetingCreation({
|
||||||
metadataLookupKey: "dailyvideo",
|
metadataLookupKey: "dailyvideo",
|
||||||
});
|
});
|
||||||
|
|
||||||
mockCalendarToHaveNoBusySlots("googlecalendar");
|
mockCalendarToHaveNoBusySlots("googlecalendar");
|
||||||
createBookingScenario(scenarioData);
|
|
||||||
|
const mockBookingData = getMockRequestDataForBooking({
|
||||||
|
data: {
|
||||||
|
eventTypeId: 1,
|
||||||
|
responses: {
|
||||||
|
email: booker.email,
|
||||||
|
name: booker.name,
|
||||||
|
location: { optionValue: "", value: "integrations:daily" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { req } = createMockNextJsRequest({
|
||||||
|
method: "POST",
|
||||||
|
body: mockBookingData,
|
||||||
|
});
|
||||||
|
|
||||||
const createdBooking = await handleNewBooking(req);
|
const createdBooking = await handleNewBooking(req);
|
||||||
expect(createdBooking.responses).toContain({
|
expect(createdBooking.responses).toContain({
|
||||||
|
@ -267,22 +264,127 @@ describe.sequential("handleNewBooking", () => {
|
||||||
|
|
||||||
expectWorkflowToBeTriggered();
|
expectWorkflowToBeTriggered();
|
||||||
|
|
||||||
const testEmails = emails.get();
|
expectBookingRequestedEmails({
|
||||||
expect(testEmails).toHaveEmail({
|
booker,
|
||||||
htmlToContain: "<title>event_awaiting_approval_subject</title>",
|
organizer,
|
||||||
to: `${organizer.email}`,
|
emails,
|
||||||
}, `${organizer.email}`);
|
})
|
||||||
|
|
||||||
expect(testEmails).toHaveEmail({
|
expectBookingRequestedWebhookToHaveBeenFired({
|
||||||
htmlToContain: "<title>booking_submitted_subject</title>",
|
booker,
|
||||||
to: `${booker.email}`,
|
organizer,
|
||||||
}, `${booker.email}`);
|
location: "integrations:daily",
|
||||||
|
subscriberUrl
|
||||||
|
})
|
||||||
|
},
|
||||||
|
timeout
|
||||||
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
`should create a booking for event that requires confirmation based on a booking notice duration threshold, if threshold is not met
|
||||||
|
1. Should create a booking in the database with status ACCEPTED
|
||||||
|
2. Should send emails to the booker as well as organizer
|
||||||
|
3. Should trigger BOOKING_CREATED webhook
|
||||||
|
`,
|
||||||
|
async ({ emails }) => {
|
||||||
|
const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default;
|
||||||
|
const booker = getBooker({
|
||||||
|
email: "booker@example.com",
|
||||||
|
name: "Booker",
|
||||||
|
});
|
||||||
|
|
||||||
|
const organizer = getOrganizer({
|
||||||
|
name: "Organizer",
|
||||||
|
email: "organizer@example.com",
|
||||||
|
id: 101,
|
||||||
|
schedules: [TestData.schedules.IstWorkHours],
|
||||||
|
credentials: [getGoogleCalendarCredential()],
|
||||||
|
selectedCalendars: [TestData.selectedCalendars.google],
|
||||||
|
});
|
||||||
|
|
||||||
|
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: 45,
|
||||||
|
requiresConfirmation: true,
|
||||||
|
metadata: {
|
||||||
|
requiresConfirmationThreshold: {
|
||||||
|
time: 30,
|
||||||
|
unit: "minutes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
length: 45,
|
||||||
|
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: "integrations:daily" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { req } = createMockNextJsRequest({
|
||||||
|
method: "POST",
|
||||||
|
body: mockBookingData,
|
||||||
|
});
|
||||||
|
|
||||||
|
const createdBooking = await handleNewBooking(req);
|
||||||
|
expect(createdBooking.responses).toContain({
|
||||||
|
email: booker.email,
|
||||||
|
name: booker.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(createdBooking).toContain({
|
||||||
|
location: "integrations:daily",
|
||||||
|
});
|
||||||
|
|
||||||
|
expectBookingToBeInDatabase({
|
||||||
|
description: "",
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
id: createdBooking.id!,
|
||||||
|
eventTypeId: mockBookingData.eventTypeId,
|
||||||
|
status: BookingStatus.ACCEPTED,
|
||||||
|
});
|
||||||
|
|
||||||
|
expectWorkflowToBeTriggered();
|
||||||
|
|
||||||
|
expectSuccessfulBookingCreationEmails({booker, organizer, emails})
|
||||||
|
|
||||||
expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", {
|
expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", {
|
||||||
triggerEvent: "BOOKING_REQUESTED",
|
triggerEvent: "BOOKING_CREATED",
|
||||||
payload: {
|
payload: {
|
||||||
metadata: {
|
metadata: {
|
||||||
// In a Pending Booking Request, we don't send the video call url
|
videoCallUrl: `${WEBAPP_URL}/video/DYNAMIC_UID`,
|
||||||
},
|
},
|
||||||
responses: {
|
responses: {
|
||||||
name: { label: "your_name", value: "Booker" },
|
name: { label: "your_name", value: "Booker" },
|
||||||
|
@ -298,6 +400,118 @@ describe.sequential("handleNewBooking", () => {
|
||||||
timeout
|
timeout
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
`should create a booking for event that requires confirmation based on a booking notice duration threshold, if threshold IS MET
|
||||||
|
1. Should create a booking in the database with status PENDING
|
||||||
|
2. Should send emails to the booker as well as organizer for booking request and awaiting approval
|
||||||
|
3. Should trigger BOOKING_REQUESTED webhook
|
||||||
|
`,
|
||||||
|
async ({ emails }) => {
|
||||||
|
const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default;
|
||||||
|
const subscriberUrl = "http://my-webhook.example.com";
|
||||||
|
const booker = getBooker({
|
||||||
|
email: "booker@example.com",
|
||||||
|
name: "Booker",
|
||||||
|
});
|
||||||
|
|
||||||
|
const organizer = getOrganizer({
|
||||||
|
name: "Organizer",
|
||||||
|
email: "organizer@example.com",
|
||||||
|
id: 101,
|
||||||
|
schedules: [TestData.schedules.IstWorkHours],
|
||||||
|
credentials: [getGoogleCalendarCredential()],
|
||||||
|
selectedCalendars: [TestData.selectedCalendars.google],
|
||||||
|
});
|
||||||
|
|
||||||
|
createBookingScenario(getScenarioData({
|
||||||
|
webhooks: [
|
||||||
|
{
|
||||||
|
userId: organizer.id,
|
||||||
|
eventTriggers: ["BOOKING_CREATED"],
|
||||||
|
subscriberUrl,
|
||||||
|
active: true,
|
||||||
|
eventTypeId: 1,
|
||||||
|
appId: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
eventTypes: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
slotInterval: 45,
|
||||||
|
requiresConfirmation: true,
|
||||||
|
metadata: {
|
||||||
|
requiresConfirmationThreshold: {
|
||||||
|
time: 120,
|
||||||
|
unit: "hours"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
length: 45,
|
||||||
|
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: "integrations:daily" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { req } = createMockNextJsRequest({
|
||||||
|
method: "POST",
|
||||||
|
body: mockBookingData,
|
||||||
|
});
|
||||||
|
|
||||||
|
const createdBooking = await handleNewBooking(req);
|
||||||
|
expect(createdBooking.responses).toContain({
|
||||||
|
email: booker.email,
|
||||||
|
name: booker.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(createdBooking).toContain({
|
||||||
|
location: "integrations:daily",
|
||||||
|
});
|
||||||
|
|
||||||
|
expectBookingToBeInDatabase({
|
||||||
|
description: "",
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
id: createdBooking.id!,
|
||||||
|
eventTypeId: mockBookingData.eventTypeId,
|
||||||
|
status: BookingStatus.PENDING,
|
||||||
|
});
|
||||||
|
|
||||||
|
expectWorkflowToBeTriggered();
|
||||||
|
|
||||||
|
expectBookingRequestedEmails({booker, organizer, emails})
|
||||||
|
|
||||||
|
expectBookingRequestedWebhookToHaveBeenFired({
|
||||||
|
booker,
|
||||||
|
organizer,
|
||||||
|
location: "integrations:daily",
|
||||||
|
subscriberUrl
|
||||||
|
})
|
||||||
|
},
|
||||||
|
timeout
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
test(
|
test(
|
||||||
`if booking with Cal Video(Daily Video) fails, booking creation fails with uncaught error`,
|
`if booking with Cal Video(Daily Video) fails, booking creation fails with uncaught error`,
|
||||||
async ({}) => {
|
async ({}) => {
|
||||||
|
@ -307,21 +521,8 @@ describe.sequential("handleNewBooking", () => {
|
||||||
name: "Booker",
|
name: "Booker",
|
||||||
});
|
});
|
||||||
const organizer = TestData.users.example;
|
const organizer = TestData.users.example;
|
||||||
const { req } = createMockNextJsRequest({
|
|
||||||
method: "POST",
|
|
||||||
body: getMockRequestDataForBooking({
|
|
||||||
data: {
|
|
||||||
eventTypeId: 1,
|
|
||||||
responses: {
|
|
||||||
email: booker.email,
|
|
||||||
name: booker.name,
|
|
||||||
location: { optionValue: "", value: "integrations:daily" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const scenarioData = {
|
createBookingScenario( {
|
||||||
hosts: [],
|
hosts: [],
|
||||||
eventTypes: [
|
eventTypes: [
|
||||||
{
|
{
|
||||||
|
@ -345,14 +546,27 @@ describe.sequential("handleNewBooking", () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
|
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
|
||||||
};
|
});
|
||||||
|
|
||||||
mockErrorOnVideoMeetingCreation({
|
mockErrorOnVideoMeetingCreation({
|
||||||
metadataLookupKey: "dailyvideo",
|
metadataLookupKey: "dailyvideo",
|
||||||
});
|
});
|
||||||
|
|
||||||
mockCalendarToHaveNoBusySlots("googlecalendar");
|
mockCalendarToHaveNoBusySlots("googlecalendar");
|
||||||
|
|
||||||
createBookingScenario(scenarioData);
|
const { req } = createMockNextJsRequest({
|
||||||
|
method: "POST",
|
||||||
|
body: getMockRequestDataForBooking({
|
||||||
|
data: {
|
||||||
|
eventTypeId: 1,
|
||||||
|
responses: {
|
||||||
|
email: booker.email,
|
||||||
|
name: booker.name,
|
||||||
|
location: { optionValue: "", value: "integrations:daily" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await handleNewBooking(req);
|
await handleNewBooking(req);
|
||||||
|
@ -381,22 +595,7 @@ describe.sequential("handleNewBooking", () => {
|
||||||
credentials: [getZoomAppCredential()],
|
credentials: [getZoomAppCredential()],
|
||||||
selectedCalendars: [TestData.selectedCalendars.google],
|
selectedCalendars: [TestData.selectedCalendars.google],
|
||||||
});
|
});
|
||||||
|
createBookingScenario(getScenarioData({
|
||||||
const { req } = createMockNextJsRequest({
|
|
||||||
method: "POST",
|
|
||||||
body: getMockRequestDataForBooking({
|
|
||||||
data: {
|
|
||||||
eventTypeId: 1,
|
|
||||||
responses: {
|
|
||||||
email: booker.email,
|
|
||||||
name: booker.name,
|
|
||||||
location: { optionValue: "", value: "integrations:zoom" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const bookingScenario = getScenarioData({
|
|
||||||
organizer,
|
organizer,
|
||||||
eventTypes: [
|
eventTypes: [
|
||||||
{
|
{
|
||||||
|
@ -421,24 +620,27 @@ describe.sequential("handleNewBooking", () => {
|
||||||
appId: null,
|
appId: null,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
}));
|
||||||
|
|
||||||
createBookingScenario(bookingScenario);
|
|
||||||
mockSuccessfulVideoMeetingCreation({
|
mockSuccessfulVideoMeetingCreation({
|
||||||
metadataLookupKey: "zoomvideo",
|
metadataLookupKey: "zoomvideo",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { req } = createMockNextJsRequest({
|
||||||
|
method: "POST",
|
||||||
|
body: getMockRequestDataForBooking({
|
||||||
|
data: {
|
||||||
|
eventTypeId: 1,
|
||||||
|
responses: {
|
||||||
|
email: booker.email,
|
||||||
|
name: booker.name,
|
||||||
|
location: { optionValue: "", value: "integrations:zoom" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
await handleNewBooking(req);
|
await handleNewBooking(req);
|
||||||
|
|
||||||
const testEmails = emails.get();
|
expectSuccessfulBookingCreationEmails({booker, organizer, emails})
|
||||||
expect(testEmails).toHaveEmail({
|
|
||||||
htmlToContain: "<title>confirmed_event_type_subject</title>",
|
|
||||||
to: `${organizer.email}`,
|
|
||||||
}, `${organizer.email}`);
|
|
||||||
|
|
||||||
expect(testEmails).toHaveEmail({
|
|
||||||
htmlToContain: "<title>confirmed_event_type_subject</title>",
|
|
||||||
to: `${booker.name} <${booker.email}>`,
|
|
||||||
}, `${booker.name} <${booker.email}>`);
|
|
||||||
|
|
||||||
expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", {
|
expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", {
|
||||||
triggerEvent: "BOOKING_CREATED",
|
triggerEvent: "BOOKING_CREATED",
|
||||||
|
@ -459,6 +661,7 @@ describe.sequential("handleNewBooking", () => {
|
||||||
},
|
},
|
||||||
timeout
|
timeout
|
||||||
);
|
);
|
||||||
|
|
||||||
describe("Paid Events", ()=>{
|
describe("Paid Events", ()=>{
|
||||||
test(
|
test(
|
||||||
`Event Type that doesn't require confirmation
|
`Event Type that doesn't require confirmation
|
||||||
|
@ -483,23 +686,7 @@ describe.sequential("handleNewBooking", () => {
|
||||||
selectedCalendars: [TestData.selectedCalendars.google],
|
selectedCalendars: [TestData.selectedCalendars.google],
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockBookingData = getMockRequestDataForBooking({
|
createBookingScenario(getScenarioData({
|
||||||
data: {
|
|
||||||
eventTypeId: 1,
|
|
||||||
responses: {
|
|
||||||
email: booker.email,
|
|
||||||
name: booker.name,
|
|
||||||
location: { optionValue: "", value: "integrations:daily" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const { req } = createMockNextJsRequest({
|
|
||||||
method: "POST",
|
|
||||||
body: mockBookingData,
|
|
||||||
});
|
|
||||||
|
|
||||||
const scenarioData = getScenarioData({
|
|
||||||
webhooks: [
|
webhooks: [
|
||||||
{
|
{
|
||||||
userId: organizer.id,
|
userId: organizer.id,
|
||||||
|
@ -517,6 +704,7 @@ describe.sequential("handleNewBooking", () => {
|
||||||
requiresConfirmation: false,
|
requiresConfirmation: false,
|
||||||
metadata: {
|
metadata: {
|
||||||
apps: {
|
apps: {
|
||||||
|
// EventType is connected to stripe.
|
||||||
stripe: {
|
stripe: {
|
||||||
price: 100,
|
price: 100,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
@ -538,31 +726,40 @@ describe.sequential("handleNewBooking", () => {
|
||||||
TestData.apps["daily-video"],
|
TestData.apps["daily-video"],
|
||||||
TestData.apps["stripe-payment"],
|
TestData.apps["stripe-payment"],
|
||||||
],
|
],
|
||||||
});
|
}));
|
||||||
|
|
||||||
mockSuccessfulVideoMeetingCreation({
|
mockSuccessfulVideoMeetingCreation({
|
||||||
metadataLookupKey: "dailyvideo",
|
metadataLookupKey: "dailyvideo",
|
||||||
});
|
});
|
||||||
|
|
||||||
const { paymentUid, externalId } = mockPaymentApp({
|
const { paymentUid, externalId } = mockPaymentApp({
|
||||||
metadataLookupKey: "stripe",
|
metadataLookupKey: "stripe",
|
||||||
appStoreLookupKey: "stripepayment",
|
appStoreLookupKey: "stripepayment",
|
||||||
});
|
});
|
||||||
|
|
||||||
mockCalendarToHaveNoBusySlots("googlecalendar");
|
mockCalendarToHaveNoBusySlots("googlecalendar");
|
||||||
createBookingScenario(scenarioData);
|
const mockBookingData = getMockRequestDataForBooking({
|
||||||
|
data: {
|
||||||
|
eventTypeId: 1,
|
||||||
|
responses: {
|
||||||
|
email: booker.email,
|
||||||
|
name: booker.name,
|
||||||
|
location: { optionValue: "", value: "integrations:daily" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { req } = createMockNextJsRequest({
|
||||||
|
method: "POST",
|
||||||
|
body: mockBookingData,
|
||||||
|
});
|
||||||
const createdBooking = await handleNewBooking(req);
|
const createdBooking = await handleNewBooking(req);
|
||||||
|
|
||||||
expect(createdBooking.responses).toContain({
|
expect(createdBooking.responses).toContain({
|
||||||
email: booker.email,
|
email: booker.email,
|
||||||
name: booker.name,
|
name: booker.name,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(createdBooking).toContain({
|
expect(createdBooking).toContain({
|
||||||
location: "integrations:daily",
|
location: "integrations:daily",
|
||||||
paymentUid: paymentUid,
|
paymentUid: paymentUid,
|
||||||
});
|
});
|
||||||
|
|
||||||
expectBookingToBeInDatabase({
|
expectBookingToBeInDatabase({
|
||||||
description: "",
|
description: "",
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
@ -570,16 +767,8 @@ describe.sequential("handleNewBooking", () => {
|
||||||
eventTypeId: mockBookingData.eventTypeId,
|
eventTypeId: mockBookingData.eventTypeId,
|
||||||
status: BookingStatus.PENDING,
|
status: BookingStatus.PENDING,
|
||||||
});
|
});
|
||||||
|
|
||||||
expectWorkflowToBeTriggered();
|
expectWorkflowToBeTriggered();
|
||||||
|
expectAwaitingPaymentEmails({organizer, booker, emails})
|
||||||
const testEmails = emails.get();
|
|
||||||
|
|
||||||
expect(testEmails).toHaveEmail({
|
|
||||||
htmlToContain: "<title>awaiting_payment_subject</title>",
|
|
||||||
to: `${booker.name} <${booker.email}>`,
|
|
||||||
}, `${booker.name} <${booker.email}>`);
|
|
||||||
|
|
||||||
expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", {
|
expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", {
|
||||||
triggerEvent: "BOOKING_PAYMENT_INITIATED",
|
triggerEvent: "BOOKING_PAYMENT_INITIATED",
|
||||||
payload: {
|
payload: {
|
||||||
|
@ -596,7 +785,9 @@ describe.sequential("handleNewBooking", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const {webhookResponse} = await mockPaymentSuccessWebhookFromStripe({externalId});
|
const {webhookResponse} = await mockPaymentSuccessWebhookFromStripe({externalId});
|
||||||
|
|
||||||
expect(webhookResponse?.statusCode).toBe(200)
|
expect(webhookResponse?.statusCode).toBe(200)
|
||||||
expectBookingToBeInDatabase({
|
expectBookingToBeInDatabase({
|
||||||
description: "",
|
description: "",
|
||||||
|
@ -605,7 +796,6 @@ describe.sequential("handleNewBooking", () => {
|
||||||
eventTypeId: mockBookingData.eventTypeId,
|
eventTypeId: mockBookingData.eventTypeId,
|
||||||
status: BookingStatus.ACCEPTED,
|
status: BookingStatus.ACCEPTED,
|
||||||
});
|
});
|
||||||
|
|
||||||
expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", {
|
expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", {
|
||||||
triggerEvent: "BOOKING_CREATED",
|
triggerEvent: "BOOKING_CREATED",
|
||||||
payload: {
|
payload: {
|
||||||
|
@ -636,6 +826,7 @@ describe.sequential("handleNewBooking", () => {
|
||||||
`,
|
`,
|
||||||
async ({ emails }) => {
|
async ({ emails }) => {
|
||||||
const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default;
|
const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default;
|
||||||
|
const subscriberUrl = "http://my-webhook.example.com"
|
||||||
const booker = getBooker({
|
const booker = getBooker({
|
||||||
email: "booker@example.com",
|
email: "booker@example.com",
|
||||||
name: "Booker",
|
name: "Booker",
|
||||||
|
@ -650,12 +841,12 @@ describe.sequential("handleNewBooking", () => {
|
||||||
selectedCalendars: [TestData.selectedCalendars.google],
|
selectedCalendars: [TestData.selectedCalendars.google],
|
||||||
});
|
});
|
||||||
|
|
||||||
const scenarioData = getScenarioData({
|
createBookingScenario(getScenarioData({
|
||||||
webhooks: [
|
webhooks: [
|
||||||
{
|
{
|
||||||
userId: organizer.id,
|
userId: organizer.id,
|
||||||
eventTriggers: ["BOOKING_CREATED"],
|
eventTriggers: ["BOOKING_CREATED"],
|
||||||
subscriberUrl: "http://my-webhook.example.com",
|
subscriberUrl,
|
||||||
active: true,
|
active: true,
|
||||||
eventTypeId: 1,
|
eventTypeId: 1,
|
||||||
appId: null,
|
appId: null,
|
||||||
|
@ -689,8 +880,16 @@ describe.sequential("handleNewBooking", () => {
|
||||||
TestData.apps["daily-video"],
|
TestData.apps["daily-video"],
|
||||||
TestData.apps["stripe-payment"],
|
TestData.apps["stripe-payment"],
|
||||||
],
|
],
|
||||||
|
}));
|
||||||
|
mockSuccessfulVideoMeetingCreation({
|
||||||
|
metadataLookupKey: "dailyvideo",
|
||||||
});
|
});
|
||||||
createBookingScenario(scenarioData);
|
const { paymentUid, externalId } = mockPaymentApp({
|
||||||
|
metadataLookupKey: "stripe",
|
||||||
|
appStoreLookupKey: "stripepayment",
|
||||||
|
});
|
||||||
|
mockCalendarToHaveNoBusySlots("googlecalendar");
|
||||||
|
|
||||||
|
|
||||||
const mockBookingData = getMockRequestDataForBooking({
|
const mockBookingData = getMockRequestDataForBooking({
|
||||||
data: {
|
data: {
|
||||||
|
@ -702,34 +901,20 @@ describe.sequential("handleNewBooking", () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
mockSuccessfulVideoMeetingCreation({
|
|
||||||
metadataLookupKey: "dailyvideo",
|
|
||||||
});
|
|
||||||
|
|
||||||
const { paymentUid, externalId } = mockPaymentApp({
|
|
||||||
metadataLookupKey: "stripe",
|
|
||||||
appStoreLookupKey: "stripepayment",
|
|
||||||
});
|
|
||||||
|
|
||||||
mockCalendarToHaveNoBusySlots("googlecalendar");
|
|
||||||
|
|
||||||
const { req } = createMockNextJsRequest({
|
const { req } = createMockNextJsRequest({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: mockBookingData,
|
body: mockBookingData,
|
||||||
});
|
});
|
||||||
|
|
||||||
const createdBooking = await handleNewBooking(req);
|
const createdBooking = await handleNewBooking(req);
|
||||||
|
|
||||||
expect(createdBooking.responses).toContain({
|
expect(createdBooking.responses).toContain({
|
||||||
email: booker.email,
|
email: booker.email,
|
||||||
name: booker.name,
|
name: booker.name,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(createdBooking).toContain({
|
expect(createdBooking).toContain({
|
||||||
location: "integrations:daily",
|
location: "integrations:daily",
|
||||||
paymentUid: paymentUid,
|
paymentUid: paymentUid,
|
||||||
});
|
});
|
||||||
|
|
||||||
expectBookingToBeInDatabase({
|
expectBookingToBeInDatabase({
|
||||||
description: "",
|
description: "",
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
@ -737,16 +922,8 @@ describe.sequential("handleNewBooking", () => {
|
||||||
eventTypeId: mockBookingData.eventTypeId,
|
eventTypeId: mockBookingData.eventTypeId,
|
||||||
status: BookingStatus.PENDING,
|
status: BookingStatus.PENDING,
|
||||||
});
|
});
|
||||||
|
|
||||||
expectWorkflowToBeTriggered();
|
expectWorkflowToBeTriggered();
|
||||||
|
expectAwaitingPaymentEmails({organizer, booker, emails})
|
||||||
const testEmails = emails.get();
|
|
||||||
|
|
||||||
expect(testEmails).toHaveEmail({
|
|
||||||
htmlToContain: "<title>awaiting_payment_subject</title>",
|
|
||||||
to: `${booker.name} <${booker.email}>`,
|
|
||||||
}, `${booker.name} <${booker.email}>`);
|
|
||||||
|
|
||||||
expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", {
|
expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", {
|
||||||
triggerEvent: "BOOKING_PAYMENT_INITIATED",
|
triggerEvent: "BOOKING_PAYMENT_INITIATED",
|
||||||
payload: {
|
payload: {
|
||||||
|
@ -764,10 +941,9 @@ describe.sequential("handleNewBooking", () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const {webhookResponse} = await mockPaymentSuccessWebhookFromStripe({externalId});
|
const {webhookResponse} = await mockPaymentSuccessWebhookFromStripe({externalId});
|
||||||
|
|
||||||
expect(webhookResponse?.statusCode).toBe(200)
|
expect(webhookResponse?.statusCode).toBe(200)
|
||||||
|
|
||||||
expectBookingToBeInDatabase({
|
expectBookingToBeInDatabase({
|
||||||
description: "",
|
description: "",
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
@ -775,23 +951,13 @@ describe.sequential("handleNewBooking", () => {
|
||||||
eventTypeId: mockBookingData.eventTypeId,
|
eventTypeId: mockBookingData.eventTypeId,
|
||||||
status: BookingStatus.PENDING,
|
status: BookingStatus.PENDING,
|
||||||
});
|
});
|
||||||
|
expectBookingRequestedWebhookToHaveBeenFired({
|
||||||
expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", {
|
booker,
|
||||||
triggerEvent: "BOOKING_REQUESTED",
|
organizer,
|
||||||
payload: {
|
location: "integrations:daily",
|
||||||
// FIXME: File this bug and link ticket here. This is a bug in the code. metadata must be sent here like other BOOKING_CREATED webhook
|
subscriberUrl,
|
||||||
metadata: null,
|
paidEvent: true
|
||||||
location: "integrations:daily",
|
})
|
||||||
responses: {
|
|
||||||
name: { label: "name", value: "Booker" },
|
|
||||||
email: { label: "email", value: "booker@example.com" },
|
|
||||||
location: {
|
|
||||||
label: "location",
|
|
||||||
value: { optionValue: "", value: "integrations:daily" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
timeout
|
timeout
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue