Files
calendar/packages/features/CalendarEventBuilder.test.ts
T
Udit TakkarGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
f2a44279fe refactor: evt calendar event builder (#27203)
* refactor: evt creation

* refactor: evt creation

* refactor: evt creation

* fix: type

* test: update unit tests

* chore: add comments

* fix: handle undefined in withConditional to match NonNullable<T> type

Co-Authored-By: unknown <>

* refactor: evt

* fix: type err

* refactor: remove add videoCallData

* refactor: use error with code

* test: update unit test

* refactor: feedback

* refactor: remove conditional

* refactor: more strict types

* fix: type err

* chor: remove un used

* refactor:  improve recurring event handling in RegularBookingService

Removed unnecessary whitespace and clarified comments regarding the attachment of recurring configurations in the booking handler. Adjusted logic to ensure that recurring settings are only applied when relevant.

* refactor: test

* fix: type error

* refactor: improve code

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-03-19 03:50:48 +09:00

1916 lines
59 KiB
TypeScript

import dayjs from "@calcom/dayjs";
import type { BookingForCalEventBuilder } from "@calcom/features/CalendarEventBuilder";
import { CalendarEventBuilder } from "@calcom/features/CalendarEventBuilder";
import { TimeFormat } from "@calcom/lib/timeFormat";
import type { CalendarEvent, Person } from "@calcom/types/Calendar";
import type { TFunction } from "i18next";
import { describe, expect, it, vi } from "vitest";
vi.mock("@calcom/features/ee/organizations/lib/getBookerUrlServer", () => ({
getBookerBaseUrl: vi.fn(async () => "https://cal.com"),
}));
vi.mock("@calcom/i18n/server", () => ({
getTranslation: vi.fn(async () => vi.fn(() => "translated")),
}));
vi.mock("@calcom/features/bookings/lib/getCalEventResponses", () => ({
getCalEventResponses: vi.fn(() => ({
responses: {
name: { label: "your_name", value: "Test User", isHidden: false },
email: { label: "email_address", value: "test@example.com", isHidden: false },
},
userFieldsResponses: {},
})),
}));
vi.mock("@calcom/prisma", () => ({
default: {},
prisma: {},
}));
describe("CalendarEventBuilder", () => {
const mockTranslate = vi.fn(() => "foo") as TFunction;
const mockStartTime = dayjs().add(1, "day").format();
const mockEndTime = dayjs().add(1, "day").add(30, "minutes").format();
const defaultOrganizer = {
id: 123,
name: "Organizer",
email: "organizer@example.com",
timeZone: "America/New_York",
language: {
translate: mockTranslate,
locale: "en",
},
};
const defaultAttendees = [
{
name: "Attendee",
email: "attendee@example.com",
timeZone: "Europe/London",
language: {
translate: mockTranslate,
locale: "en",
},
},
];
const createBuilder = (overrides: Partial<CalendarEvent> = {}) =>
new CalendarEventBuilder({
bookerUrl: "https://cal.com/user/test-slug",
title: "Test Event",
startTime: mockStartTime,
endTime: mockEndTime,
type: "test-slug",
organizer: defaultOrganizer,
attendees: defaultAttendees,
...overrides,
});
it("should create a basic calendar event", () => {
const event = createBuilder({ additionalNotes: "Some notes" })
.withEventType({
description: "Test description",
id: 123,
})
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.bookerUrl).toBe("https://cal.com/user/test-slug");
expect(event.title).toBe("Test Event");
expect(event.startTime).toBe(mockStartTime);
expect(event.endTime).toBe(mockEndTime);
expect(event.additionalNotes).toBe("Some notes");
}
});
it("should create an event with event type details", () => {
const event = createBuilder()
.withEventType({
description: "Test description",
id: 123,
hideCalendarNotes: true,
hideCalendarEventDetails: false,
})
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.type).toBe("test-slug");
expect(event.description).toBe("Test description");
expect(event.eventTypeId).toBe(123);
expect(event.hideCalendarNotes).toBe(true);
expect(event.hideCalendarEventDetails).toBe(false);
}
});
it("should create an event with organizer details", () => {
const organizer = {
id: 456,
name: "John Doe",
email: "john@example.com",
username: "johndoe",
timeZone: "America/New_York",
language: {
translate: mockTranslate,
locale: "en",
},
};
const event = createBuilder({ organizer })
.withEventType({
id: 123,
})
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.organizer).toEqual(organizer);
}
});
it("should create an event with attendees", () => {
const attendees: Person[] = [
{
email: "attendee1@example.com",
name: "Attendee One",
timeZone: "Europe/London",
language: {
translate: mockTranslate,
locale: "en",
},
},
{
email: "attendee2@example.com",
name: "Attendee Two",
timeZone: "Europe/Paris",
language: {
translate: mockTranslate,
locale: "fr",
},
},
];
const event = createBuilder({ attendees, bookerUrl: "https://cal.com/user" })
.withEventType({
id: 123,
})
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.attendees).toEqual(attendees);
}
});
it("should create an event with metadata and responses", () => {
const customInputs = { question1: "answer1" };
const responses = {
name: { label: "your_name", value: "Owner 1", isHidden: false },
email: {
label: "email_address",
value: "owner1-dunder@example.com",
isHidden: false,
},
};
const userFieldsResponses = {};
const event = createBuilder()
.withEventType({
id: 123,
})
.withMetadataAndResponses({
additionalNotes: "Some notes",
customInputs,
responses,
userFieldsResponses,
})
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.additionalNotes).toBe("Some notes");
expect(event.customInputs).toEqual(customInputs);
expect(event.responses).toEqual(responses);
expect(event.userFieldsResponses).toEqual(userFieldsResponses);
}
});
it("should create an event with location", () => {
const event = createBuilder()
.withEventType({
id: 123,
})
.withLocation({
location: "Conference Room A",
conferenceCredentialId: 789,
})
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.location).toBe("Conference Room A");
expect(event.conferenceCredentialId).toBe(789);
}
});
it("should create an event with destination calendar", () => {
const destinationCalendar = {
id: 1,
integration: "google_calendar",
externalId: "external123",
primaryEmail: "primary@example.com",
userId: null,
eventTypeId: null,
credentialId: null,
createdAt: null,
updatedAt: null,
delegationCredentialId: null,
domainWideDelegationCredentialId: null,
};
const event = createBuilder()
.withEventType({
id: 123,
})
.withDestinationCalendar([destinationCalendar])
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.destinationCalendar).toEqual([destinationCalendar]);
}
});
it("should create an event with identifiers", () => {
const event = createBuilder()
.withEventType({
id: 123,
})
.withIdentifiers({
iCalUID: "ical-123",
iCalSequence: 2,
})
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.iCalUID).toBe("ical-123");
expect(event.iCalSequence).toBe(2);
}
});
it("should create an event with confirmation settings", () => {
const event = createBuilder()
.withEventType({
id: 123,
})
.withConfirmation({
requiresConfirmation: true,
isConfirmedByDefault: false,
})
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.requiresConfirmation).toBe(true);
expect(event.oneTimePassword).toBeUndefined();
}
});
it("should set oneTimePassword to null when isConfirmedByDefault is true", () => {
const event = createBuilder()
.withEventType({
id: 123,
})
.withConfirmation({
requiresConfirmation: true,
isConfirmedByDefault: true,
})
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.requiresConfirmation).toBe(true);
expect(event.oneTimePassword).toBeNull();
}
});
it("should create an event with platform variables", () => {
const event = createBuilder()
.withEventType({
id: 123,
})
.withPlatformVariables({
platformClientId: "client-123",
platformRescheduleUrl: "https://platform.com/reschedule",
platformCancelUrl: "https://platform.com/cancel",
platformBookingUrl: "https://platform.com/booking",
})
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.platformClientId).toBe("client-123");
expect(event.platformRescheduleUrl).toBe("https://platform.com/reschedule");
expect(event.platformCancelUrl).toBe("https://platform.com/cancel");
expect(event.platformBookingUrl).toBe("https://platform.com/booking");
}
});
it("should create an event with apps status", () => {
const appsStatus = [
{
appName: "google-calendar",
type: "google_calendar",
success: 1,
failures: 0,
errors: [],
warnings: [],
},
{
appName: "Google Meet",
type: "conferencing",
success: 1,
failures: 0,
errors: [],
warnings: undefined,
},
];
const event = createBuilder()
.withEventType({
id: 123,
})
.withAppsStatus(appsStatus)
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.appsStatus).toEqual(appsStatus);
}
});
it("should create an event with video call data", () => {
const videoCallData = {
type: "google_meet",
id: "123",
url: "https://meet.example.com/123",
password: "password123",
};
const event = createBuilder()
.withEventType({
id: 123,
})
.withVideoCallData(videoCallData)
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.videoCallData).toEqual(videoCallData);
}
});
it("should create an event with team information", () => {
const team = {
name: "Engineering Team",
members: [
{
email: "member1@example.com",
name: "Member One",
timeZone: "America/Chicago",
language: {
translate: mockTranslate,
locale: "en",
},
},
],
id: 101,
};
const event = createBuilder()
.withEventType({
id: 123,
})
.withTeam(team)
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.team).toEqual(team);
}
});
it("should create an event with recurring event information", () => {
const recurringEvent = {
count: 5,
freq: 2,
interval: 1,
};
const event = createBuilder()
.withEventType({
id: 123,
})
.withRecurring(recurringEvent)
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.recurringEvent).toEqual(recurringEvent);
}
});
it("should create an event with attendee seat ID", () => {
const event = createBuilder()
.withEventType({
id: 123,
})
.withAttendeeSeatId("seat-123")
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.attendeeSeatId).toBe("seat-123");
}
});
it("should create an event with UID", () => {
const event = createBuilder()
.withEventType({
id: 123,
})
.withUid("booking-uid-123")
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.uid).toBe("booking-uid-123");
}
});
it("should create an event with one-time password", () => {
const event = createBuilder()
.withEventType({
id: 123,
})
.withOneTimePassword("otp123")
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.oneTimePassword).toBe("otp123");
}
});
it("should create an event with recurring event ID", () => {
const event = createBuilder()
.withEventType({
id: 123,
})
.withRecurringEventId("recurring-123")
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.existingRecurringEvent).toEqual({
recurringEventId: "recurring-123",
});
}
});
it("should create an event with assignment reason", () => {
const event = createBuilder()
.withEventType({
id: 123,
})
.withAssignmentReason({
category: "routed",
details: "Language: English, Region: US",
})
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.assignmentReason).toEqual({
category: "routed",
details: "Language: English, Region: US",
});
}
});
it("should create an event with assignment reason without details", () => {
const event = createBuilder()
.withEventType({
id: 123,
})
.withAssignmentReason({
category: "reassigned",
details: null,
})
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.assignmentReason).toEqual({
category: "reassigned",
details: null,
});
}
});
it("should create an event with null assignment reason", () => {
const event = createBuilder()
.withEventType({
id: 123,
})
.withAssignmentReason(null)
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.assignmentReason).toBeNull();
}
});
it("should create a complete calendar event with all properties", () => {
const organizer = {
id: 456,
name: "John Doe",
email: "john@example.com",
username: "johndoe",
timeZone: "America/New_York",
language: {
translate: mockTranslate,
locale: "en",
},
};
const attendees = [
{
email: "attendee@example.com",
name: "Attendee",
timeZone: "Europe/London",
language: {
translate: mockTranslate,
locale: "en",
},
},
];
const event = createBuilder({
type: "complete-test",
organizer,
attendees,
title: "Complete Test Event",
additionalNotes: "Complete test notes",
})
.withEventType({
description: "Complete test description",
id: 123,
hideCalendarNotes: true,
hideCalendarEventDetails: false,
})
.withMetadataAndResponses({
customInputs: { question1: "answer1" },
responses: {
name: { label: "your_name", value: "Owner 1", isHidden: false },
email: {
label: "email_address",
value: "owner1-dunder@example.com",
isHidden: false,
},
},
})
.withLocation({
location: "Conference Room A",
})
.withDestinationCalendar([
{
id: 1,
integration: "google_calendar",
externalId: "external123",
primaryEmail: "primary@example.com",
userId: 1,
eventTypeId: 123,
credentialId: 1,
createdAt: null,
updatedAt: null,
delegationCredentialId: null,
domainWideDelegationCredentialId: null,
},
])
.withIdentifiers({
iCalUID: "ical-123",
iCalSequence: 2,
})
.withConfirmation({
requiresConfirmation: true,
isConfirmedByDefault: false,
})
.withPlatformVariables({
platformClientId: "client-123",
})
.withAppsStatus([
{
appName: "google-calendar",
type: "google_calendar",
success: 1,
failures: 0,
errors: [],
warnings: [],
},
])
.withVideoCallData({
type: "google_meet",
id: "123",
url: "https://meet.example.com/123",
password: "password123",
})
.withTeam({
name: "Engineering Team",
members: [],
id: 101,
})
.withRecurring({
count: 5,
freq: 2,
interval: 1,
})
.withAttendeeSeatId("seat-123")
.withUid("booking-uid-123")
.withOneTimePassword("otp123")
.build();
// Test that all properties are set correctly
expect(event).not.toBeNull();
if (event) {
expect(event.title).toBe("Complete Test Event");
expect(event.type).toBe("complete-test");
expect(event.organizer.name).toBe("John Doe");
expect(event.attendees).toHaveLength(1);
expect(event.location).toBe("Conference Room A");
expect(event.iCalUID).toBe("ical-123");
expect(event.requiresConfirmation).toBe(true);
expect(event.platformClientId).toBe("client-123");
expect(event.appsStatus).toHaveLength(1);
expect(event.videoCallData?.url).toBe("https://meet.example.com/123");
expect(event.team?.name).toBe("Engineering Team");
expect(event.recurringEvent?.count).toBe(5);
expect(event.attendeeSeatId).toBe("seat-123");
expect(event.uid).toBe("booking-uid-123");
expect(event.oneTimePassword).toBe("otp123");
}
});
it("should create an event from an existing event", () => {
const existingEvent = {
title: "Existing Event",
startTime: mockStartTime,
endTime: mockEndTime,
type: "existing-type",
bookerUrl: "https://cal.com/user/test-slug",
organizer: defaultOrganizer,
attendees: defaultAttendees,
};
const event = CalendarEventBuilder.fromEvent({ ...existingEvent, title: "Updated Event" }).build();
expect(event).not.toBeNull();
if (event) {
expect(event.title).toBe("Updated Event");
expect(event.type).toBe("existing-type");
}
});
it("should propagate disableCancelling and disableRescheduling", () => {
const event = createBuilder({ additionalNotes: "Some notes" })
.withEventType({
description: "Test description",
id: 123,
disableCancelling: true,
disableRescheduling: true,
})
.build();
expect(event).not.toBeNull();
if (event) {
expect(event.disableCancelling).toBe(true);
expect(event.disableRescheduling).toBe(true);
}
});
describe("fromBooking", () => {
it("should create a calendar event from a basic booking", async () => {
const mockBooking = {
uid: "booking-123",
metadata: null,
title: "Test Booking",
startTime: new Date(mockStartTime),
endTime: new Date(mockEndTime),
description: "Test booking description",
location: "Conference Room A",
responses: {
name: { label: "your_name", value: "John Doe" },
email: { label: "email_address", value: "john@example.com" },
},
customInputs: null,
iCalUID: "ical-uid-123",
iCalSequence: 1,
oneTimePassword: null,
attendees: [
{
name: "Attendee One",
email: "attendee1@example.com",
timeZone: "America/New_York",
locale: "en",
phoneNumber: null,
},
],
user: {
id: 1,
name: "Organizer Name",
email: "organizer@example.com",
username: "organizer",
timeZone: "America/Los_Angeles",
locale: "en",
timeFormat: 12,
destinationCalendar: null,
profiles: [],
},
destinationCalendar: null,
eventType: {
id: 100,
slug: "test-event",
title: "60 minutes",
description: "Test event description",
hideCalendarNotes: false,
hideCalendarEventDetails: false,
hideOrganizerEmail: false,
schedulingType: null,
seatsPerTimeSlot: null,
seatsShowAttendees: false,
seatsShowAvailabilityCount: false,
customReplyToEmail: null,
disableRescheduling: false,
disableCancelling: false,
requiresConfirmation: false,
recurringEvent: null,
bookingFields: [],
metadata: null,
eventName: null,
team: null,
users: [],
hosts: [],
workflows: [],
},
references: [],
seatsReferences: [],
} satisfies BookingForCalEventBuilder;
const eventFromBooking = await CalendarEventBuilder.fromBooking(mockBooking);
const builtEvent = eventFromBooking.build();
expect(builtEvent).not.toBeNull();
if (builtEvent) {
expect(builtEvent.uid).toBe("booking-123");
expect(builtEvent.title).toBe("Test Booking");
expect(builtEvent.startTime).toBe(new Date(mockStartTime).toISOString());
expect(builtEvent.endTime).toBe(new Date(mockEndTime).toISOString());
expect(builtEvent.additionalNotes).toBe("Test booking description");
expect(builtEvent.location).toBe("Conference Room A");
expect(builtEvent.type).toBe("test-event");
expect(builtEvent.eventTypeId).toBe(100);
expect(builtEvent.organizer.name).toBe("Organizer Name");
expect(builtEvent.organizer.email).toBe("organizer@example.com");
expect(builtEvent.attendees).toHaveLength(1);
expect(builtEvent.attendees[0].email).toBe("attendee1@example.com");
expect(builtEvent.iCalUID).toBe("ical-uid-123");
expect(builtEvent.iCalSequence).toBe(1);
}
});
it("should create a calendar event from booking with video call data", async () => {
const mockBooking = {
uid: "booking-456",
metadata: null,
title: "Video Meeting",
startTime: new Date(mockStartTime),
endTime: new Date(mockEndTime),
description: null,
location: "integrations:zoom",
responses: null,
customInputs: null,
iCalUID: null,
iCalSequence: 0,
oneTimePassword: null,
attendees: [
{
name: "Attendee Two",
email: "attendee2@example.com",
timeZone: "Europe/London",
locale: "en",
phoneNumber: null,
},
],
user: {
id: 2,
name: "Host Name",
email: "host@example.com",
username: "host",
timeZone: "UTC",
locale: "en",
timeFormat: 24,
destinationCalendar: null,
profiles: [],
},
destinationCalendar: null,
eventType: {
id: 200,
title: "60 minutes",
slug: "video-call",
description: "Video call event",
hideCalendarNotes: false,
hideCalendarEventDetails: false,
hideOrganizerEmail: false,
schedulingType: null,
seatsPerTimeSlot: null,
seatsShowAttendees: false,
seatsShowAvailabilityCount: false,
customReplyToEmail: null,
disableRescheduling: false,
disableCancelling: false,
requiresConfirmation: false,
recurringEvent: null,
bookingFields: [],
metadata: null,
eventName: null,
team: null,
users: [],
hosts: [],
workflows: [],
},
references: [
{
type: "zoom_video",
uid: "123423432sdqnwhdh",
meetingId: "zoom-123",
meetingPassword: "password123",
meetingUrl: "https://zoom.us/j/123",
},
],
seatsReferences: [],
} satisfies BookingForCalEventBuilder;
const eventFromBooking = await CalendarEventBuilder.fromBooking(mockBooking);
const builtEvent = eventFromBooking.build();
expect(builtEvent).not.toBeNull();
if (builtEvent) {
expect(builtEvent.videoCallData).toBeDefined();
expect(builtEvent.videoCallData?.type).toBe("zoom_video");
expect(builtEvent.videoCallData?.id).toBe("zoom-123");
expect(builtEvent.videoCallData?.password).toBe("password123");
expect(builtEvent.videoCallData?.url).toBe("https://zoom.us/j/123");
expect(builtEvent.appsStatus).toHaveLength(1);
expect(builtEvent.appsStatus?.[0].type).toBe("zoom_video");
}
});
it("should create a calendar event from booking with team", async () => {
// Note: The CalendarEventBuilder filters team members to only include hosts
// whose emails appear in booking.attendees. This simulates a COLLECTIVE event
// where all hosts are assigned to the booking.
const mockBooking = {
uid: "booking-789",
metadata: null,
title: "Team Meeting",
startTime: new Date(mockStartTime),
endTime: new Date(mockEndTime),
description: "Team event description",
location: "Office",
responses: null,
customInputs: null,
iCalUID: null,
iCalSequence: 0,
oneTimePassword: null,
attendees: [
{
name: "Client",
email: "client@example.com",
timeZone: "America/Chicago",
locale: "en",
phoneNumber: null,
},
{
// Team member host - included in attendees for COLLECTIVE events
name: "Team Member",
email: "member@example.com",
timeZone: "America/Los_Angeles",
locale: "en",
phoneNumber: null,
},
],
user: {
id: 3,
name: "Team Lead",
email: "lead@example.com",
username: "lead",
timeZone: "America/New_York",
locale: "en",
timeFormat: 12,
destinationCalendar: {
id: 1,
integration: "google_calendar",
externalId: "external-1",
primaryEmail: "lead@example.com",
userId: 3,
eventTypeId: null,
credentialId: 1,
createdAt: null,
updatedAt: null,
delegationCredentialId: null,
domainWideDelegationCredentialId: null,
},
profiles: [],
},
destinationCalendar: null,
eventType: {
title: "60 minutes",
id: 300,
slug: "team-event",
description: "Team event",
hideCalendarNotes: false,
hideCalendarEventDetails: false,
hideOrganizerEmail: false,
schedulingType: "COLLECTIVE",
seatsPerTimeSlot: null,
seatsShowAttendees: false,
seatsShowAvailabilityCount: false,
customReplyToEmail: null,
disableRescheduling: false,
disableCancelling: false,
requiresConfirmation: false,
recurringEvent: null,
bookingFields: [],
metadata: null,
eventName: null,
team: {
id: 10,
name: "Engineering Team",
parentId: null,
members: [],
},
users: [],
hosts: [
{
userId: 3,
isFixed: true,
user: {
id: 3,
name: "Team Lead",
email: "lead@example.com",
username: "lead",
timeZone: "America/New_York",
locale: "en",
timeFormat: 12,
destinationCalendar: {
id: 1,
integration: "google_calendar",
externalId: "external-1",
primaryEmail: "lead@example.com",
userId: 3,
eventTypeId: null,
credentialId: 1,
createdAt: null,
updatedAt: null,
delegationCredentialId: null,
domainWideDelegationCredentialId: null,
},
},
},
{
userId: 4,
isFixed: false,
user: {
id: 4,
name: "Team Member",
email: "member@example.com",
username: "member",
timeZone: "America/Los_Angeles",
locale: "en",
timeFormat: 24,
destinationCalendar: {
id: 2,
integration: "google_calendar",
externalId: "external-2",
primaryEmail: "member@example.com",
userId: 4,
eventTypeId: null,
credentialId: 2,
createdAt: null,
updatedAt: null,
delegationCredentialId: null,
domainWideDelegationCredentialId: null,
},
},
},
],
workflows: [],
},
references: [],
seatsReferences: [],
} satisfies BookingForCalEventBuilder;
const eventFromBooking = await CalendarEventBuilder.fromBooking(mockBooking);
const builtEvent = eventFromBooking.build();
expect(builtEvent).not.toBeNull();
if (builtEvent) {
expect(builtEvent.team).toBeDefined();
expect(builtEvent.team?.id).toBe(10);
expect(builtEvent.team?.name).toBe("Engineering Team");
expect(builtEvent.team?.members).toHaveLength(1); // Excludes organizer
expect(builtEvent.team?.members[0].email).toBe("member@example.com");
expect(builtEvent.destinationCalendar).toHaveLength(3); // 2 hosts + 1 user calendar
expect(builtEvent.schedulingType).toBe("COLLECTIVE");
}
});
it("should create a calendar event from booking with recurring event", async () => {
const mockBooking = {
uid: "booking-recurring",
metadata: null,
title: "Recurring Meeting",
startTime: new Date(mockStartTime),
endTime: new Date(mockEndTime),
description: null,
location: "Zoom",
responses: null,
customInputs: null,
iCalUID: null,
iCalSequence: 0,
oneTimePassword: null,
attendees: [
{
name: "Regular Attendee",
email: "regular@example.com",
timeZone: "America/New_York",
locale: "en",
phoneNumber: null,
},
],
user: {
id: 5,
name: "Recurring Host",
email: "recurring@example.com",
username: "recurring",
timeZone: "America/New_York",
locale: "en",
timeFormat: 12,
destinationCalendar: null,
profiles: [],
},
destinationCalendar: null,
eventType: {
title: "60 minutes",
id: 400,
slug: "recurring-event",
description: "Recurring event",
hideCalendarNotes: false,
hideCalendarEventDetails: false,
hideOrganizerEmail: false,
schedulingType: null,
seatsPerTimeSlot: null,
seatsShowAttendees: false,
seatsShowAvailabilityCount: false,
customReplyToEmail: null,
disableRescheduling: false,
disableCancelling: false,
requiresConfirmation: false,
recurringEvent: { freq: 2, count: 5, interval: 1 },
bookingFields: [],
metadata: null,
eventName: null,
team: null,
users: [],
hosts: [],
workflows: [],
},
references: [],
seatsReferences: [],
} satisfies BookingForCalEventBuilder;
const eventFromBooking = await CalendarEventBuilder.fromBooking(mockBooking);
const builtEvent = eventFromBooking.build();
expect(builtEvent).not.toBeNull();
if (builtEvent) {
expect(builtEvent.recurringEvent).toBeDefined();
expect(builtEvent.recurringEvent?.freq).toBe(2);
expect(builtEvent.recurringEvent?.count).toBe(5);
expect(builtEvent.recurringEvent?.interval).toBe(1);
}
});
it("should create a calendar event from booking with seats", async () => {
const mockBooking = {
uid: "booking-seats",
metadata: null,
title: "Webinar",
startTime: new Date(mockStartTime),
endTime: new Date(mockEndTime),
description: "Webinar description",
location: "Online",
responses: {
email: "seat@example.com",
name: "Seat Holder",
},
customInputs: null,
iCalUID: null,
iCalSequence: 0,
oneTimePassword: null,
attendees: [
{
name: "Seat Holder",
email: "seat@example.com",
timeZone: "America/New_York",
locale: "en",
phoneNumber: null,
},
],
user: {
id: 6,
name: "Webinar Host",
email: "webinar@example.com",
username: "webinar",
timeZone: "America/New_York",
locale: "en",
timeFormat: 12,
destinationCalendar: null,
profiles: [],
},
destinationCalendar: null,
eventType: {
id: 500,
title: "60 minutes",
slug: "webinar",
description: "Webinar event",
hideCalendarNotes: false,
hideCalendarEventDetails: false,
hideOrganizerEmail: false,
schedulingType: null,
seatsPerTimeSlot: 10,
seatsShowAttendees: true,
seatsShowAvailabilityCount: true,
customReplyToEmail: null,
disableRescheduling: false,
disableCancelling: false,
requiresConfirmation: false,
recurringEvent: null,
bookingFields: [],
metadata: null,
eventName: null,
team: null,
users: [],
hosts: [],
workflows: [],
},
references: [],
seatsReferences: [
{
id: 1,
referenceUid: "seat-ref-123",
attendee: {
id: 1,
email: "seat@example.com",
phoneNumber: null,
},
},
],
} satisfies BookingForCalEventBuilder;
const eventFromBooking = await CalendarEventBuilder.fromBooking(mockBooking);
const builtEvent = eventFromBooking.build();
expect(builtEvent).not.toBeNull();
if (builtEvent) {
expect(builtEvent.seatsPerTimeSlot).toBe(10);
expect(builtEvent.seatsShowAttendees).toBe(true);
expect(builtEvent.seatsShowAvailabilityCount).toBe(true);
expect(builtEvent.attendeeSeatId).toBe("seat-ref-123");
}
});
it("should create a calendar event from booking with custom inputs and responses", async () => {
const mockBooking = {
uid: "booking-custom",
metadata: null,
title: "Custom Event",
startTime: new Date(mockStartTime),
endTime: new Date(mockEndTime),
description: "Event with custom fields",
location: "TBD",
responses: {
name: { label: "your_name", value: "Custom User" },
email: { label: "email_address", value: "custom@example.com" },
customField: { label: "Custom Question", value: "Custom Answer" },
},
customInputs: { oldField: "oldValue" },
iCalUID: "custom-ical",
iCalSequence: 2,
oneTimePassword: "otp-456",
attendees: [
{
name: "Custom User",
email: "custom@example.com",
timeZone: "Europe/Paris",
locale: "fr",
phoneNumber: "+33123456789",
},
],
user: {
id: 7,
name: "Custom Host",
email: "customhost@example.com",
username: "customhost",
timeZone: "Europe/Paris",
locale: "fr",
timeFormat: 24,
destinationCalendar: null,
profiles: [],
},
destinationCalendar: null,
eventType: {
id: 600,
title: "60 minutes",
slug: "custom-event",
description: "Custom event type",
hideCalendarNotes: true,
hideCalendarEventDetails: true,
hideOrganizerEmail: true,
schedulingType: null,
seatsPerTimeSlot: null,
seatsShowAttendees: false,
seatsShowAvailabilityCount: false,
customReplyToEmail: "custom-reply@example.com",
disableRescheduling: true,
disableCancelling: true,
requiresConfirmation: true,
recurringEvent: null,
bookingFields: [
{
name: "customField",
type: "text",
label: "Custom Question",
required: true,
},
],
metadata: null,
eventName: null,
team: null,
users: [],
hosts: [],
workflows: [],
},
references: [],
seatsReferences: [],
} satisfies BookingForCalEventBuilder;
const eventFromBooking = await CalendarEventBuilder.fromBooking(mockBooking);
const builtEvent = eventFromBooking.build();
expect(builtEvent).not.toBeNull();
if (builtEvent) {
expect(builtEvent.hideCalendarNotes).toBe(true);
expect(builtEvent.hideCalendarEventDetails).toBe(true);
expect(builtEvent.hideOrganizerEmail).toBe(true);
expect(builtEvent.customReplyToEmail).toBe("custom-reply@example.com");
expect(builtEvent.disableRescheduling).toBe(true);
expect(builtEvent.disableCancelling).toBe(true);
expect(builtEvent.requiresConfirmation).toBe(true);
expect(builtEvent.oneTimePassword).toBe("otp-456");
expect(builtEvent.customInputs).toEqual({ oldField: "oldValue" });
expect(builtEvent.responses).toBeDefined();
}
});
it("should match calendar event built from booking with manually built event", async () => {
const mockBooking = {
uid: "booking-match",
metadata: null,
title: "Match Test",
startTime: new Date(mockStartTime),
endTime: new Date(mockEndTime),
description: "Match test description",
location: "Test Location",
responses: {
name: { label: "your_name", value: "Match User" },
email: { label: "email_address", value: "match@example.com" },
},
customInputs: null,
iCalUID: "match-ical",
iCalSequence: 1,
oneTimePassword: null,
attendees: [
{
name: "Match User",
email: "match@example.com",
timeZone: "America/New_York",
locale: "en",
phoneNumber: null,
},
],
user: {
id: 8,
name: "Match Host",
email: "matchhost@example.com",
username: "matchhost",
timeZone: "America/New_York",
locale: "en",
timeFormat: 12,
destinationCalendar: null,
profiles: [],
},
destinationCalendar: null,
eventType: {
id: 700,
title: "60 minutes",
slug: "match-event",
description: "Match event type",
hideCalendarNotes: false,
hideCalendarEventDetails: false,
hideOrganizerEmail: false,
schedulingType: null,
seatsPerTimeSlot: null,
seatsShowAttendees: false,
seatsShowAvailabilityCount: false,
customReplyToEmail: null,
disableRescheduling: false,
disableCancelling: false,
requiresConfirmation: false,
recurringEvent: null,
bookingFields: [],
metadata: null,
eventName: null,
team: null,
users: [],
hosts: [],
workflows: [],
},
references: [],
seatsReferences: [],
} satisfies BookingForCalEventBuilder;
const eventFromBooking = await CalendarEventBuilder.fromBooking(mockBooking);
const builtFromBooking = eventFromBooking.build();
const organizerPerson = {
id: 8,
name: "Match Host",
email: "matchhost@example.com",
username: "matchhost",
timeZone: "America/New_York",
language: { translate: mockTranslate, locale: "en" },
timeFormat: TimeFormat["TWENTY_FOUR_HOUR"],
};
const attendeePerson = {
name: "Match User",
email: "match@example.com",
timeZone: "America/New_York",
language: { translate: mockTranslate, locale: "en" },
};
const manualBuilder = createBuilder({
type: "match-event",
organizer: organizerPerson,
attendees: [attendeePerson],
bookerUrl: "https://cal.com",
title: "Match Test",
startTime: new Date(mockStartTime).toISOString(),
endTime: new Date(mockEndTime).toISOString(),
additionalNotes: "Match test description",
});
const manualEvent = manualBuilder
.withEventType({
id: 700,
description: "Match event type",
hideCalendarNotes: false,
hideCalendarEventDetails: false,
hideOrganizerEmail: false,
schedulingType: null,
seatsPerTimeSlot: null,
seatsShowAttendees: false,
seatsShowAvailabilityCount: false,
customReplyToEmail: null,
disableRescheduling: false,
disableCancelling: false,
})
.withLocation({ location: "Test Location" })
.withIdentifiers({ iCalUID: "match-ical", iCalSequence: 1 })
.withConfirmation({ requiresConfirmation: false, isConfirmedByDefault: true })
.withUid("booking-match")
.withAppsStatus([])
.build();
expect(builtFromBooking).not.toBeNull();
expect(manualEvent).not.toBeNull();
if (builtFromBooking && manualEvent) {
expect(builtFromBooking.uid).toBe(manualEvent.uid);
expect(builtFromBooking.title).toBe(manualEvent.title);
expect(builtFromBooking.startTime).toBe(manualEvent.startTime);
expect(builtFromBooking.endTime).toBe(manualEvent.endTime);
expect(builtFromBooking.type).toBe(manualEvent.type);
expect(builtFromBooking.eventTypeId).toBe(manualEvent.eventTypeId);
expect(builtFromBooking.location).toBe(manualEvent.location);
expect(builtFromBooking.organizer.email).toBe(manualEvent.organizer.email);
expect(builtFromBooking.attendees[0].email).toBe(manualEvent.attendees[0].email);
expect(builtFromBooking.iCalUID).toBe(manualEvent.iCalUID);
expect(builtFromBooking.iCalSequence).toBe(manualEvent.iCalSequence);
}
});
it("should throw error when booking is missing user", async () => {
const mockBooking = {
uid: "booking-no-user",
metadata: null,
title: "No User",
startTime: new Date(mockStartTime),
endTime: new Date(mockEndTime),
description: null,
location: null,
responses: null,
customInputs: null,
iCalUID: null,
iCalSequence: 0,
oneTimePassword: null,
attendees: [],
user: null,
destinationCalendar: null,
eventType: {
title: "60 minutes",
id: 800,
slug: "test",
description: null,
hideCalendarNotes: false,
hideCalendarEventDetails: false,
hideOrganizerEmail: false,
schedulingType: null,
seatsPerTimeSlot: null,
seatsShowAttendees: false,
seatsShowAvailabilityCount: false,
customReplyToEmail: null,
disableRescheduling: false,
disableCancelling: false,
requiresConfirmation: false,
recurringEvent: null,
bookingFields: [],
metadata: null,
eventName: null,
team: null,
users: [],
hosts: [],
workflows: [],
},
references: [],
seatsReferences: [],
} satisfies BookingForCalEventBuilder;
await expect(CalendarEventBuilder.fromBooking(mockBooking)).rejects.toThrow(
"Booking booking-no-user is missing an organizer"
);
});
it("should throw error when booking is missing eventType", async () => {
const mockBooking = {
uid: "booking-no-eventtype",
metadata: null,
title: "No EventType",
startTime: new Date(mockStartTime),
endTime: new Date(mockEndTime),
description: null,
location: null,
responses: null,
customInputs: null,
iCalUID: null,
iCalSequence: 0,
oneTimePassword: null,
attendees: [],
user: {
id: 9,
name: "User",
email: "user@example.com",
username: "user",
timeZone: "UTC",
locale: "en",
timeFormat: 12,
destinationCalendar: null,
profiles: [],
},
destinationCalendar: null,
eventType: null,
references: [],
seatsReferences: [],
} satisfies BookingForCalEventBuilder;
await expect(CalendarEventBuilder.fromBooking(mockBooking)).rejects.toThrow(
"Booking booking-no-eventtype is missing eventType"
);
});
it("should create a complete calendar event with all properties using a booking", async () => {
const startTime = new Date("2025-01-01T10:00:00.000Z");
const endTime = new Date("2025-01-01T10:30:00.000Z");
const mockBooking = {
uid: "complete-booking-uid",
metadata: null,
title: "Complete Team Event",
startTime,
endTime,
description: "Complete event description with all properties",
location: "Conference Room A",
responses: {
email: "complete@example.com",
name: "Complete User",
attendeePhoneNumber: "+1234567890",
},
customInputs: { oldCustomField: "oldValue" },
iCalUID: "complete-ical-uid",
iCalSequence: 3,
oneTimePassword: "otp-complete",
attendees: [
{
name: "Complete User",
email: "complete@example.com",
timeZone: "America/New_York",
locale: "en",
phoneNumber: "+1234567890",
},
{
name: "Guest User",
email: "guest@example.com",
timeZone: "Europe/London",
locale: "en",
phoneNumber: null,
},
{
// Team member host - included in attendees for COLLECTIVE events
name: "Team Member",
email: "member@example.com",
timeZone: "America/Los_Angeles",
locale: "en",
phoneNumber: null,
},
],
user: {
id: 100,
name: "Team Lead",
email: "lead@example.com",
username: "teamlead",
timeZone: "America/New_York",
locale: "en",
timeFormat: 12,
destinationCalendar: {
id: 10,
integration: "google_calendar",
externalId: "lead-calendar-id",
primaryEmail: "lead@example.com",
userId: 100,
eventTypeId: null,
credentialId: 10,
createdAt: null,
updatedAt: null,
delegationCredentialId: null,
domainWideDelegationCredentialId: null,
},
profiles: [{ organizationId: 1 }],
},
destinationCalendar: null,
eventType: {
id: 1000,
slug: "complete-event",
title: "60 minutes",
description: "Complete event type description",
hideCalendarNotes: true,
hideCalendarEventDetails: true,
hideOrganizerEmail: true,
schedulingType: "COLLECTIVE",
seatsPerTimeSlot: 20,
seatsShowAttendees: true,
seatsShowAvailabilityCount: true,
customReplyToEmail: "custom-reply@example.com",
disableRescheduling: true,
disableCancelling: true,
requiresConfirmation: true,
recurringEvent: { freq: 2, count: 10, interval: 1 },
bookingFields: [
{
name: "customQuestion",
type: "text",
label: "Custom Question",
required: true,
},
],
metadata: null,
eventName: null,
team: {
id: 50,
name: "Engineering Team",
parentId: 1,
members: [],
},
users: [],
hosts: [
{
userId: 100,
isFixed: true,
user: {
id: 100,
name: "Team Lead",
email: "lead@example.com",
username: "teamlead",
timeZone: "America/New_York",
locale: "en",
timeFormat: 12,
destinationCalendar: {
id: 10,
integration: "google_calendar",
externalId: "lead-calendar-id",
primaryEmail: "lead@example.com",
userId: 100,
eventTypeId: null,
credentialId: 10,
createdAt: null,
updatedAt: null,
delegationCredentialId: null,
domainWideDelegationCredentialId: null,
},
},
},
{
userId: 101,
isFixed: false,
user: {
id: 101,
name: "Team Member",
email: "member@example.com",
username: "member",
timeZone: "America/Los_Angeles",
locale: "en",
timeFormat: 24,
destinationCalendar: {
id: 11,
integration: "google_calendar",
externalId: "member-calendar-id",
primaryEmail: "member@example.com",
userId: 101,
eventTypeId: null,
credentialId: 11,
createdAt: null,
updatedAt: null,
delegationCredentialId: null,
domainWideDelegationCredentialId: null,
},
},
},
],
workflows: [],
},
references: [
{
type: "google_calendar",
uid: "",
meetingId: "google-meeting-123",
meetingPassword: "google-pass-123",
meetingUrl: "https://google.com/j/123456789",
},
{
type: "zoom_video",
uid: "_e1cj2jap9hll6e319l3jeuii9hn6khi5acpk0gr1dgn66rrd",
meetingId: "zoom-meeting-123",
meetingPassword: "zoom-pass-123",
meetingUrl: "https://zoom.us/j/123456789",
},
],
seatsReferences: [
{
id: 1,
referenceUid: "seat-ref-complete",
attendee: {
id: 1,
email: "complete@example.com",
phoneNumber: "+1234567890",
},
},
],
} satisfies BookingForCalEventBuilder;
const eventFromBooking = await CalendarEventBuilder.fromBooking(mockBooking);
const builtFromBooking = eventFromBooking.build();
expect(builtFromBooking).not.toBeNull();
if (!builtFromBooking) return;
expect(builtFromBooking.uid).toBe("complete-booking-uid");
expect(builtFromBooking.title).toBe("Complete Team Event");
expect(builtFromBooking.startTime).toBe(startTime.toISOString());
expect(builtFromBooking.endTime).toBe(endTime.toISOString());
expect(builtFromBooking.additionalNotes).toBe("Complete event description with all properties");
expect(builtFromBooking.location).toBe("Conference Room A");
expect(builtFromBooking.type).toBe("complete-event");
expect(builtFromBooking.description).toBe("Complete event type description");
expect(builtFromBooking.eventTypeId).toBe(1000);
expect(builtFromBooking.iCalUID).toBe("complete-ical-uid");
expect(builtFromBooking.iCalSequence).toBe(3);
expect(builtFromBooking.oneTimePassword).toBe("otp-complete");
expect(builtFromBooking.hideCalendarNotes).toBe(true);
expect(builtFromBooking.hideCalendarEventDetails).toBe(true);
expect(builtFromBooking.hideOrganizerEmail).toBe(true);
expect(builtFromBooking.customReplyToEmail).toBe("custom-reply@example.com");
expect(builtFromBooking.disableRescheduling).toBe(true);
expect(builtFromBooking.disableCancelling).toBe(true);
expect(builtFromBooking.requiresConfirmation).toBe(true);
expect(builtFromBooking.schedulingType).toBe("COLLECTIVE");
expect(builtFromBooking.seatsPerTimeSlot).toBe(20);
expect(builtFromBooking.seatsShowAttendees).toBe(true);
expect(builtFromBooking.seatsShowAvailabilityCount).toBe(true);
expect(builtFromBooking.attendeeSeatId).toBe("seat-ref-complete");
expect(builtFromBooking.recurringEvent).toBeDefined();
expect(builtFromBooking.recurringEvent?.freq).toBe(2);
expect(builtFromBooking.recurringEvent?.count).toBe(10);
expect(builtFromBooking.recurringEvent?.interval).toBe(1);
expect(builtFromBooking.organizer).toBeDefined();
expect(builtFromBooking.organizer.id).toBe(100);
expect(builtFromBooking.organizer.name).toBe("Team Lead");
expect(builtFromBooking.organizer.email).toBe("lead@example.com");
expect(builtFromBooking.organizer.username).toBe("teamlead");
expect(builtFromBooking.organizer.timeZone).toBe("America/New_York");
expect(builtFromBooking.attendees).toHaveLength(3);
expect(builtFromBooking.attendees[0].name).toBe("Complete User");
expect(builtFromBooking.attendees[0].email).toBe("complete@example.com");
expect(builtFromBooking.attendees[0].timeZone).toBe("America/New_York");
expect(builtFromBooking.attendees[1].name).toBe("Guest User");
expect(builtFromBooking.attendees[1].email).toBe("guest@example.com");
expect(builtFromBooking.attendees[2].name).toBe("Team Member");
expect(builtFromBooking.attendees[2].email).toBe("member@example.com");
expect(builtFromBooking.team).toBeDefined();
expect(builtFromBooking.team?.id).toBe(50);
expect(builtFromBooking.team?.name).toBe("Engineering Team");
expect(builtFromBooking.team?.members).toHaveLength(1);
expect(builtFromBooking.team?.members[0].email).toBe("member@example.com");
expect(builtFromBooking.destinationCalendar).toBeDefined();
expect(builtFromBooking.destinationCalendar).toHaveLength(3); // 2 hosts + 1 user calendar
expect(builtFromBooking.destinationCalendar?.[0].integration).toBe("google_calendar");
expect(builtFromBooking.destinationCalendar?.[1].integration).toBe("google_calendar");
expect(builtFromBooking.destinationCalendar?.[2].integration).toBe("google_calendar");
expect(builtFromBooking.videoCallData).toBeDefined();
expect(builtFromBooking.videoCallData?.type).toBe("zoom_video");
expect(builtFromBooking.videoCallData?.id).toBe("zoom-meeting-123");
expect(builtFromBooking.videoCallData?.password).toBe("zoom-pass-123");
expect(builtFromBooking.videoCallData?.url).toBe("https://zoom.us/j/123456789");
expect(builtFromBooking.appsStatus).toBeDefined();
expect(builtFromBooking.appsStatus).toHaveLength(2);
const zoomVideo = builtFromBooking.appsStatus?.find((app) => app.type === "zoom_video");
expect(zoomVideo).toBeDefined();
if (zoomVideo) {
expect(zoomVideo.type).toBe("zoom_video");
expect(zoomVideo.success).toBe(1);
expect(zoomVideo.failures).toBe(0);
}
const googleCalendar = builtFromBooking.appsStatus?.find((app) => app.type === "google_calendar");
expect(googleCalendar).toBeDefined();
if (googleCalendar) {
expect(googleCalendar.type).toBe("google_calendar");
expect(googleCalendar.success).toBe(0);
expect(googleCalendar.failures).toBe(1);
}
expect(builtFromBooking.responses).toBeDefined();
expect(builtFromBooking.userFieldsResponses).toBeDefined();
expect(builtFromBooking.customInputs).toEqual({ oldCustomField: "oldValue" });
expect(builtFromBooking.bookerUrl).toBe("https://cal.com");
});
it("should resolve app type to human-readable app name in appsStatus", async () => {
const mockBooking = {
uid: "booking-app-name-test",
metadata: null,
title: "App Name Test Event",
startTime: new Date(mockStartTime),
endTime: new Date(mockEndTime),
description: null,
location: "integrations:google:meet",
responses: null,
customInputs: null,
iCalUID: null,
iCalSequence: 0,
oneTimePassword: null,
attendees: [
{
name: "Test Attendee",
email: "attendee@example.com",
timeZone: "UTC",
locale: "en",
phoneNumber: null,
bookingSeat: null,
},
],
user: {
id: 1,
name: "Test Host",
email: "host@example.com",
username: "testhost",
timeZone: "UTC",
locale: "en",
timeFormat: 24,
destinationCalendar: null,
profiles: [],
},
destinationCalendar: null,
eventType: {
id: 1,
title: "Test Event Type",
slug: "test-event",
description: null,
hideCalendarNotes: false,
hideCalendarEventDetails: false,
hideOrganizerEmail: false,
schedulingType: null,
seatsPerTimeSlot: null,
seatsShowAttendees: false,
seatsShowAvailabilityCount: false,
customReplyToEmail: null,
disableRescheduling: false,
disableCancelling: false,
requiresConfirmation: false,
recurringEvent: null,
bookingFields: [],
metadata: null,
eventName: null,
team: null,
users: [],
hosts: [],
workflows: [],
},
references: [
{
type: "google_calendar",
uid: "google-cal-uid-123",
meetingId: null,
meetingPassword: null,
meetingUrl: null,
},
{
type: "google_video",
uid: "google-meet-uid-456",
meetingId: "meet-123",
meetingPassword: null,
meetingUrl: "https://meet.google.com/abc-defg-hij",
},
],
seatsReferences: [],
} satisfies BookingForCalEventBuilder;
const eventFromBooking = await CalendarEventBuilder.fromBooking(mockBooking);
const builtEvent = eventFromBooking.build();
expect(builtEvent).not.toBeNull();
if (builtEvent) {
expect(builtEvent.appsStatus).toBeDefined();
expect(builtEvent.appsStatus).toHaveLength(2);
// Verify Google Calendar uses human-readable name, not the type slug
const googleCalendarStatus = builtEvent.appsStatus?.find((app) => app.type === "google_calendar");
expect(googleCalendarStatus).toBeDefined();
expect(googleCalendarStatus?.appName).toBe("Google Calendar");
// Should NOT be the raw type like "google_calendar" or "google-calendar"
expect(googleCalendarStatus?.appName).not.toBe("google_calendar");
expect(googleCalendarStatus?.appName).not.toBe("google-calendar");
// Verify Google Meet uses human-readable name
const googleMeetStatus = builtEvent.appsStatus?.find((app) => app.type === "google_video");
expect(googleMeetStatus).toBeDefined();
expect(googleMeetStatus?.appName).toBe("Google Meet");
// Should NOT be the raw type
expect(googleMeetStatus?.appName).not.toBe("google_video");
expect(googleMeetStatus?.appName).not.toBe("google-video");
}
});
});
});