perf: implement quick app store loading optimizations (#22450)
* perf: implement quick app store loading optimizations - Add conditional app store imports in videoClient and handlePayment - Implement lazy calendar manager pattern in CalendarManager - Enhance createCachedImport with better concurrency handling - Create calendar-only registry for common calendar operations - Add performance instrumentation for debugging These optimizations reduce initial app store loading time by avoiding module-level imports and creating smaller, focused registries for calendar operations. Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * fix: revert getCalendar to use appStore for proper test mocking - Reverted getCalendar.ts to use main appStore instead of calendarStore - This ensures test mocking system works properly with existing appStoreMock - Fixes unit test failures where Google Calendar references were getting null values - All collective scheduling tests now pass Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * perf: implement CalendarServiceMap for optimized calendar loading - Add CalendarServiceMap generation following CrmServiceMap pattern - Update getCalendar.ts to use generated calendar service map - Remove manual calendar-registry.ts in favor of auto-generated approach - Reduces calendar initialization from loading 48+ apps to ~10 calendar apps Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * fix: update test mocks for CalendarServiceMap compatibility - Add missing SelectedCalendar fields (createdAt, updatedAt, lastErrorAt, watchAttempts, etc.) - Fix CredentialPayload type errors by adding user.email and delegationCredentialId - Mock CalendarServiceMap to use vi.importActual for real calendar services - Ensure calendar service tests work with new lazy loading approach Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * fix: resolve CalendarServiceMap test compatibility issues - Update getCalendarsEvents.test.ts mocks to work with CalendarServiceMap dynamic imports - Add missing SelectedCalendar fields (createdAt, updatedAt, lastErrorAt, watchAttempts, etc.) - Fix CredentialPayload type errors by adding user.email and delegationCredentialId - Use type assertion in getCalendar.ts to resolve credential type conflicts - Ensure calendar service tests work with new lazy loading approach Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * fix: update test mocking for CalendarServiceMap compatibility - Add comprehensive vi.mock for calendar.services.generated in delegation-credential tests - Mock GoogleCalendarService and Office365CalendarService with proper return values - Update all test files to use await with mockCalendarToHaveNoBusySlots - Ensure calendar events return expected meetingId, meetingPassword, meetingUrl values - Fix async/await compatibility issues in booking scenario test utilities Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * fix: resolve TypeScript errors in CalendarServiceMap mocking - Extract CalendarServiceMap promise to variable to fix 'always true' condition - Ensure vi.mocked is called on Promise type for proper mockResolvedValue access - Add await keywords to calendar mock calls in test files - Maintain existing functionality while making code type-safe Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * Remove Exchange 2013 and 2016 * Mock Exchange in all tests * Fix tests * Remove exchange 2013 and 2016 from app store index * Fix merge error * Await when getting calendar service * Fix selectedSlot test * Add missing variable * Update openapi.json * Updated CalendarService imports * try again * WIP migrate calendar apps to ES6 * Revert "WIP migrate calendar apps to ES6" This reverts commit 15bf2c83305e82050779d0bca3380fa9573db1e0. * Revert changes back to e23991024a5a455c14aa05f100a5b56288db343a This reverts all calendar service changes that were causing circular dependency issues during builds and E2E tests. * Remove circular dependency for location constants * Update yarn.lock with removed package * Add empty map when running E2E * Type fies * Fix merge conflict * Remove logging statements * Throw error and reset state if failing to load app * Revert "Remove Exchange 2013 and 2016" This reverts commit fedaf6346bd9e4c63337276d5a6f9e8c3943056c. * Re-introduce exchange{2013,2016} Revert the removal in app-store/index.ts also. * Trying to fix tests --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Joe Au-Yeung <j.auyeung419@gmail.com> Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Co-authored-by: Alex van Andel <me@alexvanandel.com>
This commit is contained in:
co-authored by
Devin AI
Joe Au-Yeung
Joe Au-Yeung
Alex van Andel
parent
af07c411ee
commit
6e09489685
@@ -60,7 +60,7 @@ describe("getSchedule", () => {
|
||||
|
||||
await createDelegationCredential(org.id);
|
||||
|
||||
const googleCalendarMock = mockCalendar("googlecalendar", {
|
||||
const googleCalendarMock = await mockCalendar("googlecalendar", {
|
||||
create: {
|
||||
uid: "MOCK_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -151,7 +151,7 @@ describe("getSchedule", () => {
|
||||
// Create Delegation credential for the org user isn't part of
|
||||
await createDelegationCredential(org.id);
|
||||
|
||||
const googleCalendarMock = mockCalendar("googlecalendar", {
|
||||
const googleCalendarMock = await mockCalendar("googlecalendar", {
|
||||
create: {
|
||||
uid: "MOCK_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
createBookingScenario,
|
||||
Timezones,
|
||||
TestData,
|
||||
mockCalendarToHaveNoBusySlots,
|
||||
type ScenarioData,
|
||||
} from "../../utils/bookingScenario/bookingScenario";
|
||||
|
||||
@@ -94,6 +95,8 @@ describe("getSchedule", () => {
|
||||
|
||||
await createBookingScenario(scenarioData);
|
||||
|
||||
await mockCalendarToHaveNoBusySlots("googlecalendar");
|
||||
|
||||
const schedule = await availableSlotsService.getAvailableSlots({
|
||||
input: getTestScheduleInput({ yesterdayDateString, plus5DateString }),
|
||||
});
|
||||
@@ -129,6 +132,8 @@ describe("getSchedule", () => {
|
||||
|
||||
await createBookingScenario(scenarioData);
|
||||
|
||||
await mockCalendarToHaveNoBusySlots("googlecalendar");
|
||||
|
||||
const schedule = await availableSlotsService.getAvailableSlots({
|
||||
input: getTestScheduleInput({ yesterdayDateString, plus5DateString }),
|
||||
ctx: {
|
||||
@@ -184,6 +189,8 @@ describe("getSchedule", () => {
|
||||
|
||||
await createBookingScenario(scenarioData);
|
||||
|
||||
await mockCalendarToHaveNoBusySlots("googlecalendar");
|
||||
|
||||
const schedule = await availableSlotsService.getAvailableSlots({
|
||||
input: getTestScheduleInput({ yesterdayDateString, plus5DateString }),
|
||||
});
|
||||
@@ -239,6 +246,8 @@ describe("getSchedule", () => {
|
||||
|
||||
await createBookingScenario(scenarioData);
|
||||
|
||||
await mockCalendarToHaveNoBusySlots("googlecalendar");
|
||||
|
||||
const schedule = await availableSlotsService.getAvailableSlots({
|
||||
input: getTestScheduleInput({ yesterdayDateString, plus5DateString }),
|
||||
});
|
||||
@@ -288,6 +297,8 @@ describe("getSchedule", () => {
|
||||
|
||||
await createBookingScenario(scenarioData);
|
||||
|
||||
await mockCalendarToHaveNoBusySlots("googlecalendar");
|
||||
|
||||
const schedule = await availableSlotsService.getAvailableSlots({
|
||||
input: getTestScheduleInput({ yesterdayDateString, plus5DateString }),
|
||||
});
|
||||
|
||||
@@ -42,6 +42,15 @@ import type { CredentialForCalendarService } from "@calcom/types/Credential";
|
||||
import { getMockPaymentService } from "./MockPaymentService";
|
||||
import type { getMockRequestDataForBooking } from "./getMockRequestDataForBooking";
|
||||
|
||||
vi.mock("@calcom/app-store/calendar.services.generated", () => ({
|
||||
CalendarServiceMap: {
|
||||
googlecalendar: Promise.resolve({ default: vi.fn() }),
|
||||
office365calendar: Promise.resolve({ default: vi.fn() }),
|
||||
applecalendar: Promise.resolve({ default: vi.fn() }),
|
||||
caldavcalendar: Promise.resolve({ default: vi.fn() }),
|
||||
},
|
||||
}));
|
||||
|
||||
// We don't need to test it. Also, it causes Formbricks error when imported
|
||||
vi.mock("@calcom/lib/raqb/findTeamMembersMatchingAttributeLogic", () => ({
|
||||
default: {},
|
||||
@@ -1715,7 +1724,7 @@ export type CalendarServiceMethodMock = {
|
||||
* @param metadataLookupKey
|
||||
* @param calendarData Specify uids and other data to be faked to be returned by createEvent and updateEvent
|
||||
*/
|
||||
export function mockCalendar(
|
||||
export async function mockCalendar(
|
||||
metadataLookupKey: keyof typeof appStoreMetadata,
|
||||
calendarData?: {
|
||||
create?: {
|
||||
@@ -1749,7 +1758,7 @@ export function mockCalendar(
|
||||
updationCrash?: boolean;
|
||||
getAvailabilityCrash?: boolean;
|
||||
}
|
||||
): CalendarServiceMethodMock {
|
||||
): Promise<CalendarServiceMethodMock> {
|
||||
const appStoreLookupKey = metadataLookupKey;
|
||||
const normalizedCalendarData = calendarData || {
|
||||
create: {
|
||||
@@ -1767,138 +1776,173 @@ export function mockCalendar(
|
||||
const getAvailabilityCalls: GetAvailabilityMethodMockCall[] = [];
|
||||
const app = appStoreMetadata[metadataLookupKey as keyof typeof appStoreMetadata];
|
||||
|
||||
const appMock = appStoreMock.default[appStoreLookupKey as keyof typeof appStoreMock.default];
|
||||
const { CalendarServiceMap } = await import("@calcom/app-store/calendar.services.generated");
|
||||
const calendarServiceKey = appStoreLookupKey as keyof typeof CalendarServiceMap;
|
||||
|
||||
appMock &&
|
||||
`mockResolvedValue` in appMock &&
|
||||
appMock.mockResolvedValue({
|
||||
lib: {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
//@ts-ignore
|
||||
CalendarService: function MockCalendarService(credential: CredentialForCalendarService) {
|
||||
return {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
createEvent: async function (...rest: any[]): Promise<NewCalendarEventType> {
|
||||
if (calendarData?.creationCrash) {
|
||||
throw new Error("MockCalendarService.createEvent fake error");
|
||||
}
|
||||
const [calEvent, credentialId, externalCalendarId] = rest;
|
||||
log.debug(
|
||||
"mockCalendar.createEvent",
|
||||
JSON.stringify({ calEvent, credentialId, externalCalendarId })
|
||||
);
|
||||
createEventCalls.push({
|
||||
args: {
|
||||
calEvent,
|
||||
credentialId,
|
||||
externalCalendarId,
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
const isGoogleMeetLocation = calEvent?.location === BookingLocations.GoogleMeet;
|
||||
return Promise.resolve({
|
||||
type: app.type,
|
||||
additionalInfo: {},
|
||||
uid: "PROBABLY_UNUSED_UID",
|
||||
const calendarServicePromise = CalendarServiceMap[calendarServiceKey];
|
||||
if (calendarServicePromise) {
|
||||
const resolvedService = await calendarServicePromise;
|
||||
vi.mocked(resolvedService.default as any).mockImplementation(function MockCalendarService(
|
||||
credential: any
|
||||
) {
|
||||
return {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
createEvent: async function (...rest: any[]): Promise<NewCalendarEventType> {
|
||||
if (calendarData?.creationCrash) {
|
||||
throw new Error("MockCalendarService.createEvent fake error");
|
||||
}
|
||||
const [calEvent, credentialId, externalCalendarId] = rest;
|
||||
log.debug(
|
||||
"mockCalendar.createEvent",
|
||||
JSON.stringify({ calEvent, credentialId, externalCalendarId })
|
||||
);
|
||||
createEventCalls.push({
|
||||
args: {
|
||||
calEvent,
|
||||
credentialId,
|
||||
externalCalendarId,
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
const isGoogleMeetLocation = calEvent?.location === BookingLocations.GoogleMeet;
|
||||
if (app.type === "google_calendar") {
|
||||
return Promise.resolve({
|
||||
type: app.type,
|
||||
additionalInfo: {
|
||||
hangoutLink:
|
||||
(isGoogleMeetLocation
|
||||
? normalizedCalendarData.create?.appSpecificData?.googleCalendar?.hangoutLink
|
||||
: null) || "https://UNUSED_URL",
|
||||
// A Calendar is always expected to return an id.
|
||||
id: normalizedCalendarData.create?.id || "FALLBACK_MOCK_CALENDAR_EVENT_ID",
|
||||
iCalUID: normalizedCalendarData.create?.iCalUID,
|
||||
// Password and URL seems useless for CalendarService, plan to remove them if that's the case
|
||||
password: "MOCK_PASSWORD",
|
||||
url: "https://UNUSED_URL",
|
||||
});
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
updateEvent: async function (...rest: any[]): Promise<NewCalendarEventType> {
|
||||
if (calendarData?.updationCrash) {
|
||||
throw new Error("MockCalendarService.updateEvent fake error");
|
||||
}
|
||||
const [uid, event, externalCalendarId] = rest;
|
||||
log.silly("mockCalendar.updateEvent", JSON.stringify({ uid, event, externalCalendarId }));
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
updateEventCalls.push({
|
||||
args: {
|
||||
uid,
|
||||
event,
|
||||
externalCalendarId,
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
const isGoogleMeetLocation = event.location === BookingLocations.GoogleMeet;
|
||||
return Promise.resolve({
|
||||
type: app.type,
|
||||
additionalInfo: {},
|
||||
uid: "PROBABLY_UNUSED_UID",
|
||||
iCalUID: normalizedCalendarData.update?.iCalUID,
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
id: normalizedCalendarData.update?.uid || "FALLBACK_MOCK_ID",
|
||||
// Password and URL seems useless for CalendarService, plan to remove them if that's the case
|
||||
password: "MOCK_PASSWORD",
|
||||
url: "https://UNUSED_URL",
|
||||
location: isGoogleMeetLocation ? "https://UNUSED_URL" : undefined,
|
||||
hangoutLink:
|
||||
(isGoogleMeetLocation
|
||||
? normalizedCalendarData.update?.appSpecificData?.googleCalendar?.hangoutLink
|
||||
: null) || "https://UNUSED_URL",
|
||||
conferenceData: isGoogleMeetLocation ? event.conferenceData : undefined,
|
||||
});
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
deleteEvent: async (...rest: any[]) => {
|
||||
log.silly("mockCalendar.deleteEvent", JSON.stringify({ rest }));
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
deleteEventCalls.push({
|
||||
args: {
|
||||
uid: rest[0],
|
||||
event: rest[1],
|
||||
externalCalendarId: rest[2],
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
},
|
||||
getAvailability: async (...rest: any[]): Promise<EventBusyDate[]> => {
|
||||
if (calendarData?.getAvailabilityCrash) {
|
||||
throw new Error("MockCalendarService.getAvailability fake error");
|
||||
}
|
||||
const [dateFrom, dateTo, selectedCalendars, shouldServeCache] = rest;
|
||||
getAvailabilityCalls.push({
|
||||
args: {
|
||||
dateFrom,
|
||||
dateTo,
|
||||
selectedCalendars,
|
||||
shouldServeCache,
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
return new Promise((resolve) => {
|
||||
resolve(calendarData?.busySlots || []);
|
||||
});
|
||||
},
|
||||
};
|
||||
normalizedCalendarData.create?.appSpecificData?.googleCalendar?.hangoutLink ||
|
||||
"https://GOOGLE_MEET_URL_IN_CALENDAR_EVENT",
|
||||
},
|
||||
hangoutLink:
|
||||
normalizedCalendarData.create?.appSpecificData?.googleCalendar?.hangoutLink ||
|
||||
"https://GOOGLE_MEET_URL_IN_CALENDAR_EVENT",
|
||||
uid: normalizedCalendarData.create?.uid || "GOOGLE_CALENDAR_EVENT_ID",
|
||||
id: normalizedCalendarData.create?.id || "GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID:
|
||||
normalizedCalendarData.create?.iCalUID || calEvent.iCalUID || "GOOGLE_CALENDAR_EVENT_ID",
|
||||
password: "MOCK_PASSWORD",
|
||||
url:
|
||||
normalizedCalendarData.create?.appSpecificData?.googleCalendar?.hangoutLink ||
|
||||
"https://GOOGLE_MEET_URL_IN_CALENDAR_EVENT",
|
||||
});
|
||||
} else if (app.type === "office365_calendar") {
|
||||
return Promise.resolve({
|
||||
type: app.type,
|
||||
additionalInfo: {},
|
||||
uid: normalizedCalendarData.create?.uid || "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
id: normalizedCalendarData.create?.id || "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
iCalUID:
|
||||
normalizedCalendarData.create?.iCalUID || calEvent.iCalUID || "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
password: "MOCK_PASSWORD",
|
||||
url:
|
||||
normalizedCalendarData.create?.appSpecificData?.office365Calendar?.url ||
|
||||
"https://UNUSED_URL",
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve({
|
||||
type: app.type,
|
||||
additionalInfo: {},
|
||||
uid: "PROBABLY_UNUSED_UID",
|
||||
hangoutLink:
|
||||
(isGoogleMeetLocation
|
||||
? normalizedCalendarData.create?.appSpecificData?.googleCalendar?.hangoutLink
|
||||
: null) || "https://UNUSED_URL",
|
||||
// A Calendar is always expected to return an id.
|
||||
id: normalizedCalendarData.create?.id || "FALLBACK_MOCK_CALENDAR_EVENT_ID",
|
||||
iCalUID: normalizedCalendarData.create?.iCalUID,
|
||||
// Password and URL seems useless for CalendarService, plan to remove them if that's the case
|
||||
password: "MOCK_PASSWORD",
|
||||
url: "https://UNUSED_URL",
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
updateEvent: async function (...rest: any[]): Promise<NewCalendarEventType> {
|
||||
if (calendarData?.updationCrash) {
|
||||
throw new Error("MockCalendarService.updateEvent fake error");
|
||||
}
|
||||
const [uid, event, externalCalendarId] = rest;
|
||||
log.silly("mockCalendar.updateEvent", JSON.stringify({ uid, event, externalCalendarId }));
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
updateEventCalls.push({
|
||||
args: {
|
||||
uid,
|
||||
event,
|
||||
externalCalendarId,
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
const isGoogleMeetLocation = event.location === BookingLocations.GoogleMeet;
|
||||
return Promise.resolve({
|
||||
type: app.type,
|
||||
additionalInfo: {},
|
||||
uid: "PROBABLY_UNUSED_UID",
|
||||
iCalUID: normalizedCalendarData.update?.iCalUID,
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
id: normalizedCalendarData.update?.uid || "FALLBACK_MOCK_ID",
|
||||
// Password and URL seems useless for CalendarService, plan to remove them if that's the case
|
||||
password: "MOCK_PASSWORD",
|
||||
url: "https://UNUSED_URL",
|
||||
location: isGoogleMeetLocation ? "https://UNUSED_URL" : undefined,
|
||||
hangoutLink:
|
||||
(isGoogleMeetLocation
|
||||
? normalizedCalendarData.update?.appSpecificData?.googleCalendar?.hangoutLink
|
||||
: null) || "https://UNUSED_URL",
|
||||
conferenceData: isGoogleMeetLocation ? event.conferenceData : undefined,
|
||||
});
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
deleteEvent: async (...rest: any[]) => {
|
||||
log.silly("mockCalendar.deleteEvent", JSON.stringify({ rest }));
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
deleteEventCalls.push({
|
||||
args: {
|
||||
uid: rest[0],
|
||||
event: rest[1],
|
||||
externalCalendarId: rest[2],
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
},
|
||||
getAvailability: async (...rest: any[]): Promise<EventBusyDate[]> => {
|
||||
if (calendarData?.getAvailabilityCrash) {
|
||||
throw new Error("MockCalendarService.getAvailability fake error");
|
||||
}
|
||||
const [dateFrom, dateTo, selectedCalendars, shouldServeCache] = rest;
|
||||
getAvailabilityCalls.push({
|
||||
args: {
|
||||
dateFrom,
|
||||
dateTo,
|
||||
selectedCalendars,
|
||||
shouldServeCache,
|
||||
},
|
||||
calendarServiceConstructorArgs: {
|
||||
credential,
|
||||
},
|
||||
});
|
||||
return new Promise((resolve) => {
|
||||
resolve(calendarData?.busySlots || []);
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
createEventCalls,
|
||||
deleteEventCalls,
|
||||
updateEventCalls,
|
||||
deleteEventCalls,
|
||||
getAvailabilityCalls,
|
||||
};
|
||||
}
|
||||
|
||||
export function mockCalendarToHaveNoBusySlots(
|
||||
export async function mockCalendarToHaveNoBusySlots(
|
||||
metadataLookupKey: keyof typeof appStoreMetadata,
|
||||
calendarData?: Parameters<typeof mockCalendar>[1]
|
||||
) {
|
||||
@@ -1910,15 +1954,15 @@ export function mockCalendarToHaveNoBusySlots(
|
||||
uid: "UPDATED_MOCK_ID",
|
||||
},
|
||||
};
|
||||
return mockCalendar(metadataLookupKey, { ...calendarData, busySlots: [] });
|
||||
return await mockCalendar(metadataLookupKey, { ...calendarData, busySlots: [] });
|
||||
}
|
||||
|
||||
export function mockCalendarToCrashOnCreateEvent(metadataLookupKey: keyof typeof appStoreMetadata) {
|
||||
return mockCalendar(metadataLookupKey, { creationCrash: true });
|
||||
export async function mockCalendarToCrashOnCreateEvent(metadataLookupKey: keyof typeof appStoreMetadata) {
|
||||
return await mockCalendar(metadataLookupKey, { creationCrash: true });
|
||||
}
|
||||
|
||||
export function mockCalendarToCrashOnUpdateEvent(metadataLookupKey: keyof typeof appStoreMetadata) {
|
||||
return mockCalendar(metadataLookupKey, { updationCrash: true });
|
||||
export async function mockCalendarToCrashOnUpdateEvent(metadataLookupKey: keyof typeof appStoreMetadata) {
|
||||
return await mockCalendar(metadataLookupKey, { updationCrash: true });
|
||||
}
|
||||
|
||||
export function mockVideoApp({
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@
|
||||
"start": "turbo run start --filter=\"@calcom/web\"",
|
||||
"tdd": "vitest watch",
|
||||
"e2e": "NEXT_PUBLIC_IS_E2E=1 yarn playwright test --project=@calcom/web",
|
||||
"e2e:app-store": "QUICK=true yarn playwright test --project=@calcom/app-store",
|
||||
"e2e:app-store": "NEXT_PUBLIC_IS_E2E=1 QUICK=true yarn playwright test --project=@calcom/app-store",
|
||||
"e2e:embed": "NEXT_PUBLIC_IS_E2E=1 yarn playwright test --project=@calcom/embed-core",
|
||||
"e2e:embed-react": "QUICK=true yarn playwright test --project=@calcom/embed-react",
|
||||
"test-e2e": "yarn db-seed && yarn e2e",
|
||||
|
||||
@@ -21,7 +21,7 @@ const formatOutput = (source: string) =>
|
||||
...prettierConfig,
|
||||
});
|
||||
|
||||
const getVariableName = (appName: string) => appName.replace(/[-.]/g, "_");
|
||||
const getVariableName = (appName: string) => appName.replace(/[-.\/]/g, "_");
|
||||
|
||||
// INFO: Handle stripe separately as it's an old app with different dirName than slug/appId
|
||||
const getAppId = (app: { name: string }) => (app.name === "stripepayment" ? "stripe" : app.name);
|
||||
@@ -345,6 +345,39 @@ function generateFiles() {
|
||||
)
|
||||
);
|
||||
|
||||
const calendarOutput = [];
|
||||
const calendarServices = getExportedObject(
|
||||
"CalendarServiceMap",
|
||||
{
|
||||
importConfig: {
|
||||
fileToBeImported: "lib/CalendarService.ts",
|
||||
importName: "default",
|
||||
},
|
||||
lazyImport: true,
|
||||
},
|
||||
isCalendarApp
|
||||
);
|
||||
|
||||
// Find the export line and wrap it with E2E conditional
|
||||
const exportLineIndex = calendarServices.findIndex((line) =>
|
||||
line.startsWith("export const CalendarServiceMap")
|
||||
);
|
||||
if (exportLineIndex !== -1) {
|
||||
const exportLine = calendarServices[exportLineIndex];
|
||||
const objectContent = calendarServices.slice(exportLineIndex + 1, -1); // Remove export line and closing brace
|
||||
|
||||
calendarOutput.push(
|
||||
exportLine.replace(
|
||||
"export const CalendarServiceMap = {",
|
||||
"export const CalendarServiceMap = process.env.NEXT_PUBLIC_IS_E2E ? {} : {"
|
||||
),
|
||||
...objectContent,
|
||||
"};"
|
||||
);
|
||||
} else {
|
||||
calendarOutput.push(...calendarServices);
|
||||
}
|
||||
|
||||
const banner = `/**
|
||||
This file is autogenerated using the command \`yarn app-store:build --watch\`.
|
||||
Don't modify this file manually.
|
||||
@@ -358,6 +391,7 @@ function generateFiles() {
|
||||
["apps.keys-schemas.generated.ts", appKeysSchemasOutput],
|
||||
["bookerApps.metadata.generated.ts", bookerMetadataOutput],
|
||||
["crm.apps.generated.ts", crmOutput],
|
||||
["calendar.services.generated.ts", calendarOutput],
|
||||
];
|
||||
filesToGenerate.forEach(([fileName, output]) => {
|
||||
fs.writeFileSync(`${APP_STORE_PATH}/${fileName}`, formatOutput(`${banner}${output.join("\n")}`));
|
||||
@@ -405,3 +439,7 @@ function isBookerApp(app: App) {
|
||||
function isCrmApp(app: App) {
|
||||
return !!app.categories?.includes("crm");
|
||||
}
|
||||
|
||||
function isCalendarApp(app: App) {
|
||||
return !!app.categories?.includes("calendar");
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import logger from "@calcom/lib/logger";
|
||||
import type { Calendar, CalendarClass } from "@calcom/types/Calendar";
|
||||
import type { CredentialForCalendarService } from "@calcom/types/Credential";
|
||||
|
||||
import appStore from "..";
|
||||
import { CalendarServiceMap } from "../calendar.services.generated";
|
||||
|
||||
interface CalendarApp {
|
||||
lib: {
|
||||
@@ -36,19 +36,22 @@ export const getCalendar = async (
|
||||
calendarType = calendarType.split("_crm")[0];
|
||||
}
|
||||
|
||||
const calendarAppImportFn = appStore[calendarType.split("_").join("") as keyof typeof appStore];
|
||||
const calendarAppImportFn =
|
||||
CalendarServiceMap[calendarType.split("_").join("") as keyof typeof CalendarServiceMap];
|
||||
|
||||
if (!calendarAppImportFn) {
|
||||
log.warn(`calendar of type ${calendarType} is not implemented`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const calendarApp = await calendarAppImportFn();
|
||||
const calendarApp = await calendarAppImportFn;
|
||||
|
||||
if (!isCalendarService(calendarApp)) {
|
||||
const CalendarService = calendarApp.default;
|
||||
|
||||
if (!CalendarService || typeof CalendarService !== "function") {
|
||||
log.warn(`calendar of type ${calendarType} is not implemented`);
|
||||
return null;
|
||||
}
|
||||
const CalendarService = calendarApp.lib.CalendarService;
|
||||
return new CalendarService(credential);
|
||||
|
||||
return new CalendarService(credential as any);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import CalendarService from "@calcom/lib/CalendarService";
|
||||
import BaseCalendarService from "@calcom/lib/CalendarService";
|
||||
import type { CredentialPayload } from "@calcom/types/Credential";
|
||||
|
||||
export default class AppleCalendarService extends CalendarService {
|
||||
export default class AppleCalendarService extends BaseCalendarService {
|
||||
constructor(credential: CredentialPayload) {
|
||||
super(credential, "apple_calendar", "https://caldav.icloud.com");
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import CalendarService from "@calcom/lib/CalendarService";
|
||||
import BaseCalendarService from "@calcom/lib/CalendarService";
|
||||
import type { CredentialPayload } from "@calcom/types/Credential";
|
||||
|
||||
export default class CalDavCalendarService extends CalendarService {
|
||||
export default class CalDavCalendarService extends BaseCalendarService {
|
||||
constructor(credential: CredentialPayload) {
|
||||
super(credential, "caldav_calendar");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
This file is autogenerated using the command `yarn app-store:build --watch`.
|
||||
Don't modify this file manually.
|
||||
**/
|
||||
export const CalendarServiceMap = process.env.NEXT_PUBLIC_IS_E2E
|
||||
? {}
|
||||
: {
|
||||
applecalendar: import("./applecalendar/lib/CalendarService"),
|
||||
caldavcalendar: import("./caldavcalendar/lib/CalendarService"),
|
||||
exchange2013calendar: import("./exchange2013calendar/lib/CalendarService"),
|
||||
exchange2016calendar: import("./exchange2016calendar/lib/CalendarService"),
|
||||
exchangecalendar: import("./exchangecalendar/lib/CalendarService"),
|
||||
feishucalendar: import("./feishucalendar/lib/CalendarService"),
|
||||
googlecalendar: import("./googlecalendar/lib/CalendarService"),
|
||||
"ics-feedcalendar": import("./ics-feedcalendar/lib/CalendarService"),
|
||||
larkcalendar: import("./larkcalendar/lib/CalendarService"),
|
||||
office365calendar: import("./office365calendar/lib/CalendarService"),
|
||||
zohocalendar: import("./zohocalendar/lib/CalendarService"),
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
export const MeetLocationType = "integrations:google:meet";
|
||||
|
||||
export const MSTeamsLocationType = "integrations:office365_video";
|
||||
@@ -4,7 +4,7 @@ import type { GaxiosResponse } from "googleapis-common";
|
||||
import { RRule } from "rrule";
|
||||
import { v4 as uuid } from "uuid";
|
||||
|
||||
import { MeetLocationType } from "@calcom/app-store/locations";
|
||||
import { MeetLocationType } from "@calcom/app-store/constants";
|
||||
import { CalendarCache } from "@calcom/features/calendar-cache/calendar-cache";
|
||||
import type { FreeBusyArgs } from "@calcom/features/calendar-cache/calendar-cache.repository.interface";
|
||||
import { getTimeMax, getTimeMin } from "@calcom/features/calendar-cache/lib/datesForCache";
|
||||
|
||||
@@ -47,12 +47,29 @@ const appStore = {
|
||||
|
||||
function createCachedImport<T>(importFunc: () => Promise<T>): () => Promise<T> {
|
||||
let cachedModule: T | undefined;
|
||||
let isLoading = false;
|
||||
let loadingPromise: Promise<T> | undefined;
|
||||
|
||||
return async () => {
|
||||
if (!cachedModule) {
|
||||
cachedModule = await importFunc();
|
||||
}
|
||||
return cachedModule;
|
||||
if (cachedModule) return cachedModule;
|
||||
if (isLoading && loadingPromise) return loadingPromise;
|
||||
|
||||
isLoading = true;
|
||||
loadingPromise = importFunc()
|
||||
.then((module) => {
|
||||
cachedModule = module;
|
||||
isLoading = false;
|
||||
return module;
|
||||
})
|
||||
.catch((err) => {
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
isLoading = false;
|
||||
loadingPromise = undefined;
|
||||
});
|
||||
|
||||
return loadingPromise;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,13 @@ import { BookingStatus } from "@calcom/prisma/enums";
|
||||
import type { Ensure, Optional } from "@calcom/types/utils";
|
||||
|
||||
import type { EventLocationTypeFromAppMeta } from "../types/App";
|
||||
import {
|
||||
MeetLocationType as importedMeetLocationType,
|
||||
MSTeamsLocationType as importedMSTeamsLocationType,
|
||||
} from "./constants";
|
||||
|
||||
export const MeetLocationType = importedMeetLocationType;
|
||||
export const MSTeamsLocationType = importedMSTeamsLocationType;
|
||||
|
||||
export type DefaultEventLocationType = {
|
||||
default: true;
|
||||
@@ -64,9 +71,6 @@ export type EventLocationType = DefaultEventLocationType | EventLocationTypeFrom
|
||||
|
||||
export const DailyLocationType = "integrations:daily";
|
||||
export const CalVideoLocationType = DailyLocationType;
|
||||
export const MeetLocationType = "integrations:google:meet";
|
||||
|
||||
export const MSTeamsLocationType = "integrations:office365_video";
|
||||
|
||||
/**
|
||||
* This isn't an actual location app type. It is a special value that informs to use the Organizer's default conferencing app during booking
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Calendar as OfficeCalendar, User, Event } from "@microsoft/microsoft-graph-types-beta";
|
||||
import type { DefaultBodyType } from "msw";
|
||||
|
||||
import { MSTeamsLocationType } from "@calcom/app-store/locations";
|
||||
import { MSTeamsLocationType } from "@calcom/app-store/constants";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { getLocation, getRichDescriptionHTML } from "@calcom/lib/CalEventParser";
|
||||
import {
|
||||
|
||||
@@ -135,7 +135,7 @@ describe("handleNewBooking", () => {
|
||||
});
|
||||
|
||||
// Mock a Scenario where iCalUID isn't returned by Google Calendar in which case booking UID is used as the ics UID
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
uid: "MOCK_ID",
|
||||
@@ -191,7 +191,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
iCalUID: createdBooking.iCalUID,
|
||||
|
||||
@@ -120,7 +120,7 @@ describe("handleNewBooking", () => {
|
||||
});
|
||||
|
||||
// Mock a Scenario where iCalUID isn't returned by Google Calendar in which case booking UID is used as the ics UID
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
uid: "MOCK_ID",
|
||||
@@ -177,7 +177,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
iCalUID: createdBooking.iCalUID,
|
||||
@@ -298,7 +297,7 @@ describe("handleNewBooking", () => {
|
||||
});
|
||||
|
||||
// Mock a Scenario where iCalUID isn't returned by Google Calendar in which case booking UID is used as the ics UID
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
uid: "MOCK_ID",
|
||||
@@ -355,7 +354,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
iCalUID: createdBooking.iCalUID,
|
||||
|
||||
+108
-6
@@ -37,6 +37,7 @@ import {
|
||||
} from "@calcom/web/test/utils/bookingScenario/getMockRequestDataForBooking";
|
||||
import { setupAndTeardown } from "@calcom/web/test/utils/bookingScenario/setupAndTeardown";
|
||||
|
||||
import { vi } from "vitest";
|
||||
import { describe, expect } from "vitest";
|
||||
|
||||
import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData";
|
||||
@@ -44,6 +45,108 @@ import { BookingStatus } from "@calcom/prisma/enums";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import { test } from "@calcom/web/test/fixtures/fixtures";
|
||||
|
||||
vi.mock("@calcom/app-store/calendar.services.generated", () => {
|
||||
class MockGoogleCalendarService {
|
||||
credential: any;
|
||||
|
||||
constructor(credential: any) {
|
||||
this.credential = credential;
|
||||
}
|
||||
|
||||
getCredentialId() {
|
||||
return this.credential.id;
|
||||
}
|
||||
|
||||
async createEvent(calEvent: any, credentialId: any, externalCalendarId?: string) {
|
||||
return {
|
||||
type: "google_calendar",
|
||||
additionalInfo: {
|
||||
hangoutLink: "https://GOOGLE_MEET_URL_IN_CALENDAR_EVENT",
|
||||
},
|
||||
uid: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
id: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: calEvent.iCalUID || "GOOGLE_CALENDAR_EVENT_ID",
|
||||
password: "MOCK_PASSWORD",
|
||||
url: "https://GOOGLE_MEET_URL_IN_CALENDAR_EVENT",
|
||||
createdEvent: {
|
||||
hangoutLink: "https://GOOGLE_MEET_URL_IN_CALENDAR_EVENT",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async updateEvent() {
|
||||
return {};
|
||||
}
|
||||
|
||||
async deleteEvent() {
|
||||
return {};
|
||||
}
|
||||
|
||||
async getAvailability() {
|
||||
return [];
|
||||
}
|
||||
|
||||
async getAvailabilityWithTimeZones() {
|
||||
return [];
|
||||
}
|
||||
|
||||
async listCalendars() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
class MockOffice365CalendarService {
|
||||
credential: any;
|
||||
|
||||
constructor(credential: any) {
|
||||
this.credential = credential;
|
||||
}
|
||||
|
||||
getCredentialId() {
|
||||
return this.credential.id;
|
||||
}
|
||||
|
||||
async createEvent(calEvent: any, credentialId: any, externalCalendarId?: string) {
|
||||
return {
|
||||
type: "office365_calendar",
|
||||
additionalInfo: {},
|
||||
uid: "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
id: "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
iCalUID: calEvent.iCalUID || "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
password: "MOCK_PASSWORD",
|
||||
url: "https://UNUSED_URL",
|
||||
};
|
||||
}
|
||||
|
||||
async updateEvent() {
|
||||
return {};
|
||||
}
|
||||
|
||||
async deleteEvent() {
|
||||
return {};
|
||||
}
|
||||
|
||||
async getAvailability() {
|
||||
return [];
|
||||
}
|
||||
|
||||
async getAvailabilityWithTimeZones() {
|
||||
return [];
|
||||
}
|
||||
|
||||
async listCalendars() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
CalendarServiceMap: {
|
||||
googlecalendar: Promise.resolve({ default: MockGoogleCalendarService }),
|
||||
office365calendar: Promise.resolve({ default: MockOffice365CalendarService }),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// Local test runs sometime gets too slow
|
||||
const timeout = process.env.CI ? 5000 : 20000;
|
||||
|
||||
@@ -136,7 +239,7 @@ describe("handleNewBooking", () => {
|
||||
);
|
||||
|
||||
// Mock a Scenario where iCalUID isn't returned by Google Calendar in which case booking UID is used as the ics UID
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
uid: "MOCK_ID",
|
||||
@@ -314,7 +417,7 @@ describe("handleNewBooking", () => {
|
||||
);
|
||||
|
||||
// Mock a Scenario where iCalUID isn't returned by Google Calendar in which case booking UID is used as the ics UID
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
uid: "MOCK_ID",
|
||||
@@ -501,7 +604,7 @@ describe("handleNewBooking", () => {
|
||||
});
|
||||
|
||||
// Mock a Scenario where iCalUID isn't returned by Google Calendar in which case booking UID is used as the ics UID
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("office365calendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("office365calendar", {
|
||||
create: {
|
||||
id: "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
uid: "MOCK_ID",
|
||||
@@ -562,7 +665,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
meetingId: "OFFICE_365_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
// Verify Delegation credential was used
|
||||
delegationCredentialId: delegationCredential.id,
|
||||
},
|
||||
@@ -700,7 +802,7 @@ describe("handleNewBooking", () => {
|
||||
});
|
||||
|
||||
// Mock a Scenario where iCalUID isn't returned by Google Calendar in which case booking UID is used as the ics UID
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
uid: "MOCK_ID",
|
||||
@@ -856,7 +958,7 @@ describe("handleNewBooking", () => {
|
||||
);
|
||||
|
||||
// Mock a Scenario where iCalUID isn't returned by Google Calendar in which case booking UID is used as the ics UID
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
uid: "MOCK_ID",
|
||||
|
||||
@@ -160,7 +160,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
},
|
||||
@@ -214,7 +214,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
iCalUID: createdBooking.iCalUID,
|
||||
@@ -326,7 +325,7 @@ describe("handleNewBooking", () => {
|
||||
});
|
||||
|
||||
// Mock a Scenario where iCalUID isn't returned by Google Calendar in which case booking UID is used as the ics UID
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
uid: "MOCK_ID",
|
||||
@@ -379,7 +378,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
iCalUID: createdBooking.iCalUID,
|
||||
@@ -489,7 +487,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
uid: "MOCK_ID",
|
||||
id: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
@@ -542,7 +540,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
iCalUID: createdBooking.iCalUID,
|
||||
@@ -775,7 +772,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
uid: "MOCK_ID",
|
||||
id: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
@@ -829,7 +826,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
iCalUID: createdBooking.iCalUID,
|
||||
@@ -934,7 +930,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("applecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("applecalendar", {
|
||||
create: {
|
||||
uid: "MOCK_ID",
|
||||
id: "MOCKED_APPLE_CALENDAR_EVENT_ID",
|
||||
@@ -989,7 +985,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_APPLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_APPLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -3191,7 +3186,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
},
|
||||
@@ -3245,7 +3240,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
iCalUID: createdBooking.iCalUID,
|
||||
|
||||
+1
-2
@@ -117,7 +117,7 @@ describe("handleNewRecurringBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -195,7 +195,6 @@ describe("handleNewRecurringBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -119,7 +119,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -193,7 +193,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -338,7 +337,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -472,7 +471,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -545,7 +544,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -691,7 +689,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -764,7 +762,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -949,7 +946,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -1104,7 +1101,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -1325,7 +1322,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
|
||||
@@ -157,7 +157,7 @@ describe("handleNewBooking", () => {
|
||||
metadataLookupKey: "dailyvideo",
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
uid: "MOCK_ID",
|
||||
},
|
||||
@@ -396,7 +396,7 @@ describe("handleNewBooking", () => {
|
||||
metadataLookupKey: "dailyvideo",
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
uid: "MOCK_ID",
|
||||
},
|
||||
@@ -785,7 +785,7 @@ describe("handleNewBooking", () => {
|
||||
metadataLookupKey: "dailyvideo",
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
uid: "MOCK_ID",
|
||||
},
|
||||
@@ -1013,7 +1013,7 @@ describe("handleNewBooking", () => {
|
||||
metadataLookupKey: "dailyvideo",
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
uid: "MOCK_ID",
|
||||
},
|
||||
@@ -1261,7 +1261,7 @@ describe("handleNewBooking", () => {
|
||||
})
|
||||
);
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
uid: "MOCK_ID",
|
||||
},
|
||||
@@ -1478,7 +1478,7 @@ describe("handleNewBooking", () => {
|
||||
metadataLookupKey: "dailyvideo",
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
uid: "MOCK_ID",
|
||||
},
|
||||
@@ -1720,7 +1720,7 @@ describe("handleNewBooking", () => {
|
||||
metadataLookupKey: "dailyvideo",
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
uid: "MOCK_ID",
|
||||
},
|
||||
@@ -2908,7 +2908,7 @@ describe("handleNewBooking", () => {
|
||||
metadataLookupKey: "dailyvideo",
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: { uid: "NEW_EVENT_ID" },
|
||||
update: { uid: "UPDATED_EVENT_ID" },
|
||||
});
|
||||
|
||||
+1
-1
@@ -176,7 +176,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const organizerCalendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const organizerCalendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
update: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID_2",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID_2",
|
||||
|
||||
+9
-17
@@ -152,7 +152,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -201,7 +201,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -335,7 +334,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -457,7 +456,7 @@ describe("handleNewBooking", () => {
|
||||
url: `http://mock-dailyvideo.example.com/meeting-1`,
|
||||
},
|
||||
});
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -503,7 +502,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -682,7 +680,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -732,7 +730,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -917,7 +914,7 @@ describe("handleNewBooking", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -967,7 +964,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1412,7 +1408,7 @@ describe("handleNewBooking", () => {
|
||||
url: `http://mock-dailyvideo.example.com/meeting-1`,
|
||||
},
|
||||
});
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -1457,7 +1453,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1613,7 +1608,7 @@ describe("handleNewBooking", () => {
|
||||
url: `http://mock-zoomvideo.example.com/meeting-1`,
|
||||
},
|
||||
});
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -1657,7 +1652,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1819,7 +1813,7 @@ describe("handleNewBooking", () => {
|
||||
url: `http://mock-dailyvideo.example.com/meeting-1`,
|
||||
},
|
||||
});
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -1864,7 +1858,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -2013,7 +2006,7 @@ describe("handleNewBooking", () => {
|
||||
url: `http://mock-dailyvideo.example.com/meeting-1`,
|
||||
},
|
||||
});
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: {
|
||||
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
|
||||
@@ -2059,7 +2052,6 @@ describe("handleNewBooking", () => {
|
||||
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
|
||||
meetingPassword: "MOCK_PASSWORD",
|
||||
meetingUrl: "https://UNUSED_URL",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -108,7 +108,7 @@ describe("roundRobinReassignment test", () => {
|
||||
})
|
||||
);
|
||||
|
||||
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
const calendarMock = await mockCalendarToHaveNoBusySlots("googlecalendar", {
|
||||
create: { uid: "NEW_EVENT_ID" },
|
||||
update: { uid: "UPDATED_EVENT_ID" },
|
||||
});
|
||||
|
||||
@@ -35,7 +35,7 @@ export const getCalendarCredentials = (credentials: Array<CredentialForCalendarS
|
||||
.filter((app) => app.type.endsWith("_calendar"))
|
||||
.flatMap((app) => {
|
||||
const credentials = app.credentials.flatMap((credential) => {
|
||||
const calendar = getCalendar(credential);
|
||||
const calendar = () => getCalendar(credential);
|
||||
return app.variant === "calendar" ? [{ integration: app, credential, calendar }] : [];
|
||||
});
|
||||
|
||||
@@ -71,7 +71,18 @@ export const getConnectedCalendars = async (
|
||||
delegationCredentialId,
|
||||
};
|
||||
}
|
||||
const cals = await calendar.listCalendars();
|
||||
const calendarInstance = await calendar();
|
||||
if (!calendarInstance) {
|
||||
return {
|
||||
integration: safeToSendIntegration,
|
||||
credentialId,
|
||||
delegationCredentialId,
|
||||
error: {
|
||||
message: "Could not get calendar instance",
|
||||
},
|
||||
};
|
||||
}
|
||||
const cals = await calendarInstance.listCalendars();
|
||||
const calendars = sortBy(
|
||||
cals.map((cal: IntegrationCalendar) => {
|
||||
if (cal.externalId === destinationCalendarExternalId) destinationCalendar = cal;
|
||||
|
||||
@@ -19,6 +19,83 @@ vi.mock("./crypto", () => ({
|
||||
|
||||
const mockedSymmetricDecrypt = vi.mocked(symmetricDecrypt);
|
||||
|
||||
vi.mock("@calcom/app-store/calendar.services.generated", () => {
|
||||
class MockGoogleCalendarService {
|
||||
constructor(credential: any) {
|
||||
this.credential = credential;
|
||||
}
|
||||
|
||||
getCredentialId() {
|
||||
return this.credential.id;
|
||||
}
|
||||
|
||||
async createEvent() {
|
||||
return {};
|
||||
}
|
||||
|
||||
async updateEvent() {
|
||||
return {};
|
||||
}
|
||||
|
||||
async deleteEvent() {
|
||||
return {};
|
||||
}
|
||||
|
||||
async getAvailability() {
|
||||
return [];
|
||||
}
|
||||
|
||||
async getAvailabilityWithTimeZones() {
|
||||
return [];
|
||||
}
|
||||
|
||||
async listCalendars() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
class MockOfficeCalendarService {
|
||||
constructor(credential: any) {
|
||||
this.credential = credential;
|
||||
}
|
||||
|
||||
getCredentialId() {
|
||||
return this.credential.id;
|
||||
}
|
||||
|
||||
async createEvent() {
|
||||
return {};
|
||||
}
|
||||
|
||||
async updateEvent() {
|
||||
return {};
|
||||
}
|
||||
|
||||
async deleteEvent() {
|
||||
return {};
|
||||
}
|
||||
|
||||
async getAvailability() {
|
||||
return [];
|
||||
}
|
||||
|
||||
async getAvailabilityWithTimeZones() {
|
||||
return [];
|
||||
}
|
||||
|
||||
async listCalendars() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
CalendarServiceMap: {
|
||||
googlecalendar: vi.importActual("@calcom/app-store/googlecalendar/lib/CalendarService"),
|
||||
office365calendar: vi.importActual("@calcom/app-store/office365calendar/lib/CalendarService"),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
function buildDelegationCredential(credential: CredentialPayload): CredentialForCalendarService {
|
||||
return {
|
||||
...credential,
|
||||
@@ -87,10 +164,12 @@ describe("getCalendarsEvents", () => {
|
||||
},
|
||||
userId: 808,
|
||||
teamId: null,
|
||||
user: {
|
||||
email: "test@example.com",
|
||||
},
|
||||
appId: "exampleApp",
|
||||
invalid: false,
|
||||
delegationCredentialId: null,
|
||||
user: null,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -339,7 +418,9 @@ describe("getCalendarsEventsWithTimezones", () => {
|
||||
},
|
||||
userId: 808,
|
||||
teamId: null,
|
||||
user: null,
|
||||
user: {
|
||||
email: "test@example.com",
|
||||
},
|
||||
appId: "exampleApp",
|
||||
invalid: false,
|
||||
delegationCredentialId: null,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { AppCategories, Prisma } from "@prisma/client";
|
||||
|
||||
import appStore from "@calcom/app-store";
|
||||
import type { EventTypeAppsList } from "@calcom/app-store/utils";
|
||||
import type { CompleteEventType } from "@calcom/prisma/zod";
|
||||
import { eventTypeAppMetadataOptionalSchema } from "@calcom/prisma/zod-utils";
|
||||
@@ -52,6 +51,8 @@ const handlePayment = async ({
|
||||
}) => {
|
||||
if (isDryRun) return null;
|
||||
const key = paymentAppCredentials?.app?.dirName;
|
||||
|
||||
const appStore = await import("@calcom/app-store").then((m) => m.default);
|
||||
if (!isKeyOf(appStore, key)) {
|
||||
console.warn(`key: ${key} is not a valid key in appStore`);
|
||||
return null;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import short from "short-uuid";
|
||||
import { v5 as uuidv5 } from "uuid";
|
||||
|
||||
import appStore from "@calcom/app-store";
|
||||
import { getDailyAppKeys } from "@calcom/app-store/dailyvideo/lib/getDailyAppKeys";
|
||||
import { DailyLocationType } from "@calcom/app-store/locations";
|
||||
import { sendBrokenIntegrationEmail } from "@calcom/emails";
|
||||
@@ -27,6 +26,8 @@ const getVideoAdapters = async (withCredentials: CredentialPayload[]): Promise<V
|
||||
for (const cred of withCredentials) {
|
||||
const appName = cred.type.split("_").join(""); // Transform `zoom_video` to `zoomvideo`;
|
||||
log.silly("Getting video adapter for", safeStringify({ appName, cred: getPiiFreeCredential(cred) }));
|
||||
|
||||
const appStore = await import("@calcom/app-store").then((m) => m.default);
|
||||
const appImportFn = appStore[appName as keyof typeof appStore];
|
||||
|
||||
// Static Link Video Apps don't exist in packages/app-store/index.ts(it's manually maintained at the moment) and they aren't needed there anyway.
|
||||
|
||||
@@ -1041,7 +1041,6 @@ export class AvailableSlotsService {
|
||||
queuedFormResponseId,
|
||||
});
|
||||
}
|
||||
|
||||
const { qualifiedRRHosts, allFallbackRRHosts, fixedHosts } =
|
||||
await this.dependencies.qualifiedHostsService.findQualifiedHostsWithDelegationCredentials({
|
||||
eventType,
|
||||
|
||||
@@ -10,3 +10,46 @@ const fetchMocker = createFetchMock(vi);
|
||||
fetchMocker.enableMocks();
|
||||
|
||||
expect.extend(matchers);
|
||||
|
||||
class MockExchangeCalendarService implements CalendarService {
|
||||
constructor() {}
|
||||
async createEvent() {
|
||||
return {
|
||||
uid: "mock",
|
||||
id: "mock",
|
||||
password: "",
|
||||
type: "",
|
||||
url: "",
|
||||
additionalInfo: {},
|
||||
};
|
||||
}
|
||||
async updateEvent() {
|
||||
return {
|
||||
uid: "mock",
|
||||
id: "mock",
|
||||
password: "",
|
||||
type: "",
|
||||
url: "",
|
||||
additionalInfo: {},
|
||||
};
|
||||
}
|
||||
async deleteEvent() {}
|
||||
async getAvailability() {
|
||||
return [];
|
||||
}
|
||||
async listCalendars() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
vi.mock("@calcom/exchangecalendar/lib/CalendarService", () => ({
|
||||
default: MockExchangeCalendarService,
|
||||
}));
|
||||
|
||||
vi.mock("@calcom/exchange2013calendar/lib/CalendarService", () => ({
|
||||
default: MockExchangeCalendarService,
|
||||
}));
|
||||
|
||||
vi.mock("@calcom/exchange2016calendar/lib/CalendarService", () => ({
|
||||
default: MockExchangeCalendarService,
|
||||
}));
|
||||
|
||||
@@ -3066,32 +3066,6 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@calcom/exchange2013calendar@workspace:packages/app-store/exchange2013calendar":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/exchange2013calendar@workspace:packages/app-store/exchange2013calendar"
|
||||
dependencies:
|
||||
"@calcom/lib": "*"
|
||||
"@calcom/prisma": "*"
|
||||
"@calcom/types": "*"
|
||||
"@calcom/ui": "*"
|
||||
ews-javascript-api: ^0.11.0
|
||||
react-hook-form: ^7.43.3
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@calcom/exchange2016calendar@workspace:packages/app-store/exchange2016calendar":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/exchange2016calendar@workspace:packages/app-store/exchange2016calendar"
|
||||
dependencies:
|
||||
"@calcom/lib": "*"
|
||||
"@calcom/prisma": "*"
|
||||
"@calcom/types": "*"
|
||||
"@calcom/ui": "*"
|
||||
ews-javascript-api: ^0.11.0
|
||||
react-hook-form: ^7.43.3
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@calcom/exchangecalendar@workspace:packages/app-store/exchangecalendar":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/exchangecalendar@workspace:packages/app-store/exchangecalendar"
|
||||
|
||||
Reference in New Issue
Block a user