From 9eb3698ea5963b0f577ada30691d83d500ac1a18 Mon Sep 17 00:00:00 2001 From: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Date: Wed, 13 Sep 2023 09:49:01 +0530 Subject: [PATCH] fix: multiple organizer address bug (#11299) * fix: multiple organizer address bug Signed-off-by: Udit Takkar * fix: add inPerson condition Signed-off-by: Udit Takkar * fix: change options Signed-off-by: Udit Takkar * Send _type along with the response to be able to determine what input was it. We can use that later * Revert "Send _type along with the response to be able to determine what input was it. We can use that later" This reverts commit c75ba57ad14b07d629b218d6e3eaede93b99ebaa. * Update multiple organizer address test to verify the test fix * Add a test to ensure that sending label would correctly add that label as location --------- Signed-off-by: Udit Takkar Co-authored-by: Peer Richelsen Co-authored-by: Hariom Balhara --- apps/web/pages/booking/[uid].tsx | 2 +- apps/web/playwright/event-types.e2e.ts | 22 +++- .../bookings/lib/handleNewBooking.test.ts | 122 ++++++++++++++++++ .../form-builder/FormBuilderField.tsx | 6 +- 4 files changed, 143 insertions(+), 9 deletions(-) diff --git a/apps/web/pages/booking/[uid].tsx b/apps/web/pages/booking/[uid].tsx index a77dc76965..9d1e163c9b 100644 --- a/apps/web/pages/booking/[uid].tsx +++ b/apps/web/pages/booking/[uid].tsx @@ -461,7 +461,7 @@ export default function Success(props: SuccessProps) { {locationToDisplay && !isCancelled && ( <>
{t("where")}
-
+
{locationToDisplay.startsWith("http") ? ( { .first() .getAttribute("href"); + /** + * Verify first organizer address + */ await page.goto(previewLink ?? ""); - await selectFirstAvailableTimeSlotNextMonth(page); - - for (const location of locationData) { - await page.locator(`span:has-text("${location}")`).click(); - } - + await page.locator(`span:has-text("${locationData[0]}")`).click(); await bookTimeSlot(page); - await expect(page.locator("[data-testid=success-page]")).toBeVisible(); + await expect(page.locator(`[data-testid="where"]`)).toHaveText(locationData[0]); + + /** + * Verify second organizer address + */ + await page.goto(previewLink ?? ""); + await selectFirstAvailableTimeSlotNextMonth(page); + await page.locator(`span:has-text("${locationData[1]}")`).click(); + await bookTimeSlot(page); + await expect(page.locator("[data-testid=success-page]")).toBeVisible(); + await expect(page.locator(`[data-testid="where"]`)).toHaveText(locationData[1]); }); test.describe("Different Locations Tests", () => { diff --git a/packages/features/bookings/lib/handleNewBooking.test.ts b/packages/features/bookings/lib/handleNewBooking.test.ts index a2fb67a0ea..3832ea172c 100644 --- a/packages/features/bookings/lib/handleNewBooking.test.ts +++ b/packages/features/bookings/lib/handleNewBooking.test.ts @@ -470,6 +470,128 @@ describe.sequential("handleNewBooking", () => { }, timeout ); + test( + `should create a successful booking when location is provided as label of an option(Done for Organizer Address) + 1. Should create a booking in the database + 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], + }); + + const mockBookingData = getMockRequestDataForBooking({ + data: { + eventTypeId: 1, + responses: { + email: booker.email, + name: booker.name, + location: { optionValue: "", value: "New York" }, + }, + }, + }); + + const { req } = createMockNextJsRequest({ + method: "POST", + body: mockBookingData, + }); + + const scenarioData = 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, + length: 45, + users: [ + { + id: 101, + }, + ], + }, + ], + organizer, + apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]], + }); + + mockCalendarToHaveNoBusySlots("googlecalendar"); + createBookingScenario(scenarioData); + + const createdBooking = await handleNewBooking(req); + expect(createdBooking.responses).toContain({ + email: booker.email, + name: booker.name, + }); + + expect(createdBooking).toContain({ + location: "New York", + }); + + expectBookingToBeInDatabase({ + description: "", + eventType: { + connect: { + id: mockBookingData.eventTypeId, + }, + }, + status: BookingStatus.ACCEPTED, + }); + + expectWorkflowToBeTriggered(); + + const testEmails = emails.get(); + expect(testEmails[0]).toHaveEmail({ + htmlToContain: "confirmed_event_type_subject", + to: `${organizer.email}`, + }); + expect(testEmails[1]).toHaveEmail({ + htmlToContain: "confirmed_event_type_subject", + to: `${booker.name} <${booker.email}>`, + }); + expect(testEmails[1].html).toContain("confirmed_event_type_subject"); + expectWebhookToHaveBeenCalledWith("http://my-webhook.example.com", { + triggerEvent: "BOOKING_CREATED", + payload: { + metadata: { + }, + responses: { + name: { label: "your_name", value: "Booker" }, + email: { label: "email_address", value: "booker@example.com" }, + location: { + label: "location", + value: { optionValue: "", value: "New York" }, + }, + title: { label: "what_is_this_meeting_about" }, + notes: { label: "additional_notes" }, + guests: { label: "additional_guests" }, + rescheduleReason: { label: "reason_for_reschedule" }, + }, + }, + }); + }, + timeout + ); }); }); diff --git a/packages/features/form-builder/FormBuilderField.tsx b/packages/features/form-builder/FormBuilderField.tsx index f75f876611..e311713620 100644 --- a/packages/features/form-builder/FormBuilderField.tsx +++ b/packages/features/form-builder/FormBuilderField.tsx @@ -311,6 +311,10 @@ export const ComponentForField = ({ if (!field.optionsInputs) { throw new Error("Field optionsInputs is not defined"); } + const options = field.options.map((field) => { + return { ...field, value: field.value === "inPerson" ? field.label : field.value }; + }); + return field.options.length ? ( void} optionsInputs={field.optionsInputs} - options={field.options} + options={options} required={field.required} />