diff --git a/packages/features/instant-meeting/handleInstantMeeting.test.ts b/packages/features/instant-meeting/handleInstantMeeting.test.ts new file mode 100644 index 00000000000000..7cdce98cbce56d --- /dev/null +++ b/packages/features/instant-meeting/handleInstantMeeting.test.ts @@ -0,0 +1,203 @@ +import prismock from "../../../tests/libs/__mocks__/prisma"; + +import { + createBookingScenario, + getScenarioData, + getGoogleCalendarCredential, + TestData, + getOrganizer, + mockSuccessfulVideoMeetingCreation, + mockCalendarToHaveNoBusySlots, + mockNoTranslations, +} from "@calcom/web/test/utils/bookingScenario/bookingScenario"; + +import type { NextApiRequest } from "next"; +import { describe, it, expect, vi, beforeEach } from "vitest"; + +import { BookingStatus } from "@calcom/prisma/enums"; + +vi.mock("@calcom/features/notifications/sendNotification", () => ({ + sendNotification: vi.fn(), +})); + +vi.mock("@calcom/lib/videoClient", () => ({ + createInstantMeetingWithCalVideo: vi.fn().mockResolvedValue({ + type: "daily_video", + id: "MOCK_INSTANT_MEETING_ID", + password: "MOCK_INSTANT_PASS", + url: "http://mock-dailyvideo.example.com/instant-meeting-url", + }), +})); + +describe("handleInstantMeeting", () => { + beforeEach(() => { + mockNoTranslations(); + }); + describe("team event instant meeting", () => { + it("should successfully create instant meeting for team event", async () => { + const handler = (await import("./handleInstantMeeting")).default; + const organizer = getOrganizer({ + name: "Organizer", + email: "organizer@example.com", + id: 101, + schedules: [TestData.schedules.IstWorkHours], + credentials: [getGoogleCalendarCredential()], + selectedCalendars: [TestData.selectedCalendars.google], + }); + + const { dateString: plus1DateString } = getDate({ dateIncrement: 1 }); + + await createBookingScenario( + getScenarioData({ + eventTypes: [ + { + id: 1, + slotInterval: 45, + length: 45, + users: [ + { + id: 101, + }, + ], + team: { + id: 1, + }, + instantMeetingExpiryTimeOffsetInSeconds: 90, + }, + ], + organizer, + apps: [TestData.apps["daily-video"], TestData.apps["google-calendar"]], + }) + ); + + mockSuccessfulVideoMeetingCreation({ + metadataLookupKey: "dailyvideo", + videoMeetingData: { + id: "MOCK_ID", + password: "MOCK_PASS", + url: `http://mock-dailyvideo.example.com/meeting-1`, + }, + }); + mockCalendarToHaveNoBusySlots("googlecalendar", { + create: { + uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID", + }, + }); + + const mockReqBody = { + eventTypeId: 1, + name: "Test User", + email: "test@example.com", + timeZone: "UTC", + language: "en", + start: `${plus1DateString}T04:00:00.000Z`, + end: `${plus1DateString}T04:45:00.000Z`, + responses: { + name: "Test User", + email: "test@example.com", + }, + metadata: {}, + }; + + const mockRequest = { + body: mockReqBody, + method: "POST", + headers: {}, + query: {}, + cookies: {}, + url: "/api/instant-meeting", + } as NextApiRequest; + + const result = await handler(mockRequest); + + expect(result.message).toBe("Success"); + expect(result.bookingId).toBeDefined(); + expect(result.bookingUid).toBeDefined(); + expect(result.meetingTokenId).toBeDefined(); + expect(result.expires).toBeInstanceOf(Date); + + const booking = await prismock.booking.findUnique({ + where: { id: result.bookingId }, + include: { attendees: true, references: true }, + }); + + expect(booking).toBeDefined(); + expect(booking?.status).toBe(BookingStatus.AWAITING_HOST); + expect(booking?.attendees).toHaveLength(1); + expect(booking?.attendees[0].email).toBe("test@example.com"); + expect(booking?.references).toHaveLength(1); + expect(booking?.references[0].type).toBe("daily_video"); + }); + + it("should throw error for non-team event types", async () => { + const handler = (await import("./handleInstantMeeting")).default; + const organizer = getOrganizer({ + name: "Organizer", + email: "organizer@example.com", + id: 101, + schedules: [TestData.schedules.IstWorkHours], + credentials: [getGoogleCalendarCredential()], + selectedCalendars: [TestData.selectedCalendars.google], + }); + + const { dateString: plus1DateString } = getDate({ dateIncrement: 1 }); + + await createBookingScenario( + getScenarioData({ + eventTypes: [ + { + id: 1, + slotInterval: 45, + length: 45, + users: [ + { + id: 101, + }, + ], + }, + ], + organizer, + apps: [TestData.apps["daily-video"], TestData.apps["google-calendar"]], + }) + ); + + const mockReqBody = { + eventTypeId: 1, + name: "Test User", + email: "test@example.com", + timeZone: "UTC", + language: "en", + start: `${plus1DateString}T04:00:00.000Z`, + end: `${plus1DateString}T04:45:00.000Z`, + responses: { + name: "Test User", + email: "test@example.com", + }, + metadata: {}, + }; + + const mockRequest = { + body: mockReqBody, + method: "POST", + headers: {}, + query: {}, + cookies: {}, + url: "/api/instant-meeting", + } as NextApiRequest; + + await expect(handler(mockRequest)).rejects.toThrow( + "Only Team Event Types are supported for Instant Meeting" + ); + }); + }); +}); + +function getDate(param: { dateIncrement?: number } = {}) { + const { dateIncrement = 0 } = param; + const date = new Date(); + date.setDate(date.getDate() + dateIncrement); + return { + date, + dateString: date.toISOString().split("T")[0], + }; +}