From 13a765e50a0b7b5b4af9e4be2b4bea9f8689612f Mon Sep 17 00:00:00 2001 From: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Date: Tue, 16 Jan 2024 01:08:16 +0530 Subject: [PATCH] =?UTF-8?q?test:=20In=20Team=20Event=20type=20when=20locat?= =?UTF-8?q?ion=20is=20Organizer=20Default=20App=20and=20U=E2=80=A6=20(#129?= =?UTF-8?q?39)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: In Team Event type when location is Organizer Default App and User Metadata is emoty * chore: use variable * fix: type error --- .../utils/bookingScenario/bookingScenario.ts | 4 + .../features/bookings/lib/handleNewBooking.ts | 2 +- .../collective-scheduling.test.ts | 209 ++++++++++++++++++ packages/prisma/zod-utils.ts | 2 + 4 files changed, 216 insertions(+), 1 deletion(-) diff --git a/apps/web/test/utils/bookingScenario/bookingScenario.ts b/apps/web/test/utils/bookingScenario/bookingScenario.ts index 40e3d17662..02f863a91e 100644 --- a/apps/web/test/utils/bookingScenario/bookingScenario.ts +++ b/apps/web/test/utils/bookingScenario/bookingScenario.ts @@ -19,6 +19,7 @@ import { safeStringify } from "@calcom/lib/safeStringify"; import type { WorkflowActions, WorkflowTemplates, WorkflowTriggerEvents } from "@calcom/prisma/client"; import type { SchedulingType } from "@calcom/prisma/enums"; import type { BookingStatus } from "@calcom/prisma/enums"; +import type { userMetadataType } from "@calcom/prisma/zod-utils"; import type { AppMeta } from "@calcom/types/App"; import type { NewCalendarEventType } from "@calcom/types/Calendar"; import type { EventBusyDate, IntervalLimit } from "@calcom/types/Calendar"; @@ -887,6 +888,7 @@ export function getOrganizer({ weekStart = "Sunday", teams, organizationId, + metadata, }: { name: string; email: string; @@ -899,6 +901,7 @@ export function getOrganizer({ destinationCalendar?: Prisma.DestinationCalendarCreateInput; weekStart?: WeekDays; teams?: InputUser["teams"]; + metadata?: userMetadataType; }) { return { ...TestData.users.example, @@ -913,6 +916,7 @@ export function getOrganizer({ weekStart, teams, organizationId, + metadata, }; } diff --git a/packages/features/bookings/lib/handleNewBooking.ts b/packages/features/bookings/lib/handleNewBooking.ts index 055460cd07..b84bd91838 100644 --- a/packages/features/bookings/lib/handleNewBooking.ts +++ b/packages/features/bookings/lib/handleNewBooking.ts @@ -1325,7 +1325,7 @@ async function handler( organizerOrFirstDynamicGroupMemberDefaultLocationUrl = organizerMetadata?.defaultConferencingApp?.appLink; } else { - locationBodyString = ""; + locationBodyString = "integrations:daily"; } } diff --git a/packages/features/bookings/lib/handleNewBooking/test/team-bookings/collective-scheduling.test.ts b/packages/features/bookings/lib/handleNewBooking/test/team-bookings/collective-scheduling.test.ts index c556b04bbe..a7a444df58 100644 --- a/packages/features/bookings/lib/handleNewBooking/test/team-bookings/collective-scheduling.test.ts +++ b/packages/features/bookings/lib/handleNewBooking/test/team-bookings/collective-scheduling.test.ts @@ -3,7 +3,10 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { describe, expect } from "vitest"; import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData"; + +import { OrganizerDefaultConferencingAppType } from "@calcom/app-store/locations"; import { CAL_URL, WEBAPP_URL } from "@calcom/lib/constants"; + import { ErrorCode } from "@calcom/lib/errorCodes"; import { SchedulingType } from "@calcom/prisma/enums"; import { BookingStatus } from "@calcom/prisma/enums"; @@ -1087,6 +1090,212 @@ describe("handleNewBooking", () => { timeout ); + test( + `When event type location is Organizer Default App and user metadata is empty, default to Cal Video`, + async ({ emails }) => { + const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default; + const booker = getBooker({ + email: "booker@example.com", + name: "Booker", + }); + + const otherTeamMembers = [ + { + name: "Other Team Member 1", + username: "other-team-member-1", + timeZone: Timezones["+5:30"], + defaultScheduleId: 1001, + email: "other-team-member-1@example.com", + id: 102, + schedules: [ + { + ...TestData.schedules.IstWorkHours, + // Specify an ID directly here because we want to be able to use that ID in defaultScheduleId above. + id: 1001, + }, + ], + credentials: [getGoogleCalendarCredential()], + selectedCalendars: [TestData.selectedCalendars.google], + destinationCalendar: { + integration: TestData.apps["google-calendar"].type, + externalId: "other-team-member-1@google-calendar.com", + }, + }, + ]; + + const organizer = getOrganizer({ + name: "Organizer", + email: "organizer@example.com", + id: 101, + schedules: [TestData.schedules.IstWorkHours], + credentials: [ + { + id: 2, + ...getGoogleCalendarCredential(), + }, + { + id: 1, + ...getZoomAppCredential(), + }, + ], + metadata: {}, + selectedCalendars: [TestData.selectedCalendars.google], + destinationCalendar: { + integration: TestData.apps["google-calendar"].type, + externalId: "organizer@google-calendar.com", + }, + }); + + const { eventTypes } = 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: 45, + schedulingType: SchedulingType.COLLECTIVE, + length: 45, + users: [ + { + id: 101, + }, + { + id: 102, + }, + ], + locations: [ + { + type: "conferencing", + }, + ], + destinationCalendar: { + integration: TestData.apps["google-calendar"].type, + externalId: "event-type-1@google-calendar.com", + }, + }, + ], + organizer, + usersApartFromOrganizer: otherTeamMembers, + apps: [ + TestData.apps["google-calendar"], + TestData.apps["daily-video"], + TestData.apps["zoomvideo"], + ], + }) + ); + + mockSuccessfulVideoMeetingCreation({ + metadataLookupKey: appStoreMetadata.dailyvideo.dirName, + videoMeetingData: { + id: "MOCK_ID", + password: "MOCK_PASS", + url: `http://mock-dailyvideo.example.com/meeting-1`, + }, + }); + + const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", { + create: { + id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID", + iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID", + }, + }); + + const mockBookingData = getMockRequestDataForBooking({ + data: { + start: `${getDate({ dateIncrement: 1 }).dateString}T05:00:00.000Z`, + end: `${getDate({ dateIncrement: 1 }).dateString}T05:30:00.000Z`, + eventTypeId: 1, + responses: { + email: booker.email, + name: booker.name, + location: { optionValue: "", value: OrganizerDefaultConferencingAppType }, + }, + }, + }); + + const { req } = createMockNextJsRequest({ + method: "POST", + body: mockBookingData, + }); + + const createdBooking = await handleNewBooking(req); + + await expectBookingToBeInDatabase({ + description: "", + location: BookingLocations.CalVideo, + responses: expect.objectContaining({ + email: booker.email, + name: booker.name, + }), + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + uid: createdBooking.uid!, + eventTypeId: mockBookingData.eventTypeId, + status: BookingStatus.ACCEPTED, + references: [ + { + type: appStoreMetadata.dailyvideo.type, + uid: "MOCK_ID", + meetingId: "MOCK_ID", + meetingPassword: "MOCK_PASS", + meetingUrl: "http://mock-dailyvideo.example.com/meeting-1", + }, + { + type: TestData.apps["google-calendar"].type, + uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID", + meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID", + meetingPassword: "MOCK_PASSWORD", + meetingUrl: "https://UNUSED_URL", + }, + ], + }); + + // expectWorkflowToBeTriggered(); + + expectSuccessfulCalendarEventCreationInCalendar(calendarMock, { + destinationCalendars: [ + { + integration: TestData.apps["google-calendar"].type, + externalId: "event-type-1@google-calendar.com", + }, + { + integration: TestData.apps["google-calendar"].type, + externalId: "other-team-member-1@google-calendar.com", + }, + ], + videoCallUrl: "http://mock-dailyvideo.example.com/meeting-1", + }); + + expectSuccessfulBookingCreationEmails({ + booking: { + uid: createdBooking.uid!, + }, + booker, + organizer, + otherTeamMembers, + emails, + iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID", + }); + + expectBookingCreatedWebhookToHaveBeenFired({ + booker, + organizer, + location: OrganizerDefaultConferencingAppType, + subscriberUrl: "http://my-webhook.example.com", + videoCallUrl: `${WEBAPP_URL}/video/${createdBooking.uid}`, + }); + }, + timeout + ); + describe("Team(T1) not part of any org but the organizer is part of an organization(O1)", () => { test( `succesfully creates a booking when all the hosts are free as per their schedules diff --git a/packages/prisma/zod-utils.ts b/packages/prisma/zod-utils.ts index 48647c8bbf..d81f43ccb2 100644 --- a/packages/prisma/zod-utils.ts +++ b/packages/prisma/zod-utils.ts @@ -324,6 +324,8 @@ export const userMetadata = z }) .nullable(); +export type userMetadataType = z.infer; + export const teamMetadataSchema = z .object({ requestedSlug: z.string(),