From 07c38f1f339ada3b794d633e7cd4853d0c19c745 Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Tue, 18 Mar 2025 17:32:20 +0530 Subject: [PATCH] test: Add tests for Booker component (#19051) * feat: Don't allow unavailable slot's booking form to be visible - Send back to slots listing * Improvements * feat: Add env variables and strategies to prevent booking failures - Added new environment variables for configuring slot reservation and availability checks - Implemented strategies to handle concurrent bookings and slot availability - Updated Booker component and related files to support new reservation and slot checking mechanisms - Added README with detailed explanation of booking prevention strategies - Configured dynamic intervals for slot and reservation queries * docs: Update Booker README with detailed slot reservation and availability explanation - Clarified slot reservation behavior when multiple users access the same booking page - Added details about `getSchedule` refetching strategies and timing - Explained how slot availability is detected and communicated to users * Support for skip confirmation form flow * feat: Enhance slot availability and reservation mechanism - Refactored slot availability checking to support multiple slots - Added tentative selected timeslots to improve booking UX - Updated trpc handler to check availability for multiple slots - Introduced new store methods for managing tentative slot selections - Improved slot reservation and availability status tracking * refactor: Improve slot availability quick check mechanism - Renamed and restructured slot availability check parameters - Extracted quick availability checks into a separate hook - Updated type definitions for slot status and availability checks - Simplified slot availability logic in Booker and related components - Maintained cached state for quick availability checks * Add tests booker * Support minimu booking check too * change data-testid * Rneame * Fix race condition with uid cookie not set * fix tests * Remove unsded variable * fixup! Merge branch 'main' into dont-allow-booking-form-with-unavaialble-slot * Fix the unavailability bug when only seconds differ * Handle column view that doesnt have selected date and also add tests for isTimeSlotAavailable * Fi ts and unit tests --------- Co-authored-by: Hariom Balhara Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com> Co-authored-by: Morgan Vernay --- packages/dayjs/__mocks__/index.ts | 15 + .../features/auth/__mocks__/Turnstile.tsx | 7 + .../bookings/Booker/__mocks__/config.ts | 5 + .../bookings/Booker/__mocks__/store.ts | 37 +++ .../bookings/Booker/__tests__/Booker.test.tsx | 265 ++++++++++++++++++ .../__mocks__/OverlayCalendar.tsx | 21 ++ .../__mocks__/AvailableTimeSlots.tsx | 5 + .../components/__mocks__/DatePicker.tsx | 3 + .../components/__mocks__/DryRunMessage.tsx | 5 + .../Booker/components/__mocks__/EventMeta.tsx | 16 ++ .../Booker/components/__mocks__/Header.tsx | 4 + .../components/__mocks__/LargeCalendar.tsx | 13 + .../Booker/components/__mocks__/Section.tsx | 22 ++ .../components/__mocks__/Unavailable.tsx | 3 + packages/lib/__mocks__/constants.ts | 21 ++ packages/lib/__mocks__/logger.ts | 16 ++ packages/lib/__mocks__/next-seo.config.ts | 17 ++ .../__mocks__/UnpublishedEntity.tsx | 5 + .../{test-setup.ts => test-setup.tsx} | 21 ++ vitest.workspace.ts | 14 +- 20 files changed, 508 insertions(+), 7 deletions(-) create mode 100644 packages/dayjs/__mocks__/index.ts create mode 100644 packages/features/auth/__mocks__/Turnstile.tsx create mode 100644 packages/features/bookings/Booker/__mocks__/config.ts create mode 100644 packages/features/bookings/Booker/__mocks__/store.ts create mode 100644 packages/features/bookings/Booker/__tests__/Booker.test.tsx create mode 100644 packages/features/bookings/Booker/components/OverlayCalendar/__mocks__/OverlayCalendar.tsx create mode 100644 packages/features/bookings/Booker/components/__mocks__/AvailableTimeSlots.tsx create mode 100644 packages/features/bookings/Booker/components/__mocks__/DatePicker.tsx create mode 100644 packages/features/bookings/Booker/components/__mocks__/DryRunMessage.tsx create mode 100644 packages/features/bookings/Booker/components/__mocks__/EventMeta.tsx create mode 100644 packages/features/bookings/Booker/components/__mocks__/Header.tsx create mode 100644 packages/features/bookings/Booker/components/__mocks__/LargeCalendar.tsx create mode 100644 packages/features/bookings/Booker/components/__mocks__/Section.tsx create mode 100644 packages/features/bookings/Booker/components/__mocks__/Unavailable.tsx create mode 100644 packages/lib/__mocks__/logger.ts create mode 100644 packages/lib/__mocks__/next-seo.config.ts create mode 100644 packages/ui/components/__mocks__/UnpublishedEntity.tsx rename packages/ui/components/{test-setup.ts => test-setup.tsx} (73%) diff --git a/packages/dayjs/__mocks__/index.ts b/packages/dayjs/__mocks__/index.ts new file mode 100644 index 0000000000..762cf69650 --- /dev/null +++ b/packages/dayjs/__mocks__/index.ts @@ -0,0 +1,15 @@ +import timezone from "dayjs/plugin/timezone"; +import utc from "dayjs/plugin/utc"; + +import dayjs from "@calcom/dayjs"; + +dayjs.extend(utc); +dayjs.extend(timezone); + +const mockDayjs = vi.fn((date) => dayjs(date)); + +mockDayjs.utc = vi.fn((date) => dayjs.utc(date)); +mockDayjs.tz = vi.fn(); +mockDayjs.extend = vi.fn(); + +export default mockDayjs; diff --git a/packages/features/auth/__mocks__/Turnstile.tsx b/packages/features/auth/__mocks__/Turnstile.tsx new file mode 100644 index 0000000000..2543c9ded6 --- /dev/null +++ b/packages/features/auth/__mocks__/Turnstile.tsx @@ -0,0 +1,7 @@ +vi.mock("@calcom/features/auth/Turnstile", () => ({ + default: ({ onVerify }: { onVerify: (token: string) => void }) => ( +
onVerify("test-token")}> + Mock Captcha +
+ ), +})); diff --git a/packages/features/bookings/Booker/__mocks__/config.ts b/packages/features/bookings/Booker/__mocks__/config.ts new file mode 100644 index 0000000000..3629a432ff --- /dev/null +++ b/packages/features/bookings/Booker/__mocks__/config.ts @@ -0,0 +1,5 @@ +vi.mock("../config", () => ({ + useBookerResizeAnimation: () => ({ current: document.createElement("div") }), + getBookerSizeClassNames: () => [], + fadeInLeft: {}, +})); diff --git a/packages/features/bookings/Booker/__mocks__/store.ts b/packages/features/bookings/Booker/__mocks__/store.ts new file mode 100644 index 0000000000..31788506ea --- /dev/null +++ b/packages/features/bookings/Booker/__mocks__/store.ts @@ -0,0 +1,37 @@ +import { vi } from "vitest"; + +const mockStore = { + state: { + username: "", + eventSlug: "", + eventId: undefined, + layout: "month_view", + month: undefined, + bookingUid: null, + isTeamEvent: false, + bookingData: null, + verifiedEmail: null, + rescheduleUid: null, + rescheduledBy: null, + seatReferenceUid: undefined, + durationConfig: null, + org: null, + isInstantMeeting: false, + timezone: null, + teamMemberEmail: null, + crmOwnerRecordType: null, + crmAppSlug: null, + }, + setSelectedDate: vi.fn(), + setMonth: vi.fn(), + setTimeFormat: vi.fn(), + setLayout: vi.fn(), + setVerifiedEmail: vi.fn(), + setState: vi.fn(), +}; + +vi.mock("../store", () => ({ + useBookerStore: vi.fn(() => mockStore), +})); + +export default mockStore; diff --git a/packages/features/bookings/Booker/__tests__/Booker.test.tsx b/packages/features/bookings/Booker/__tests__/Booker.test.tsx new file mode 100644 index 0000000000..e30c83e205 --- /dev/null +++ b/packages/features/bookings/Booker/__tests__/Booker.test.tsx @@ -0,0 +1,265 @@ +import "@calcom/features/bookings/Booker/__mocks__/config"; +import "@calcom/features/bookings/Booker/components/OverlayCalendar/__mocks__/OverlayCalendar"; +import "@calcom/features/bookings/Booker/components/__mocks__/AvailableTimeSlots"; +import "@calcom/features/bookings/Booker/components/__mocks__/DatePicker"; +import "@calcom/features/bookings/Booker/components/__mocks__/DryRunMessage"; +import "@calcom/features/bookings/Booker/components/__mocks__/EventMeta"; +import "@calcom/features/bookings/Booker/components/__mocks__/Header"; +import "@calcom/features/bookings/Booker/components/__mocks__/LargeCalendar"; +import "@calcom/features/bookings/Booker/components/__mocks__/Section"; +import { constantsScenarios } from "@calcom/lib/__mocks__/constants"; +import "@calcom/lib/__mocks__/logger"; + +import { render, screen } from "@testing-library/react"; +import { vi } from "vitest"; + +import "@calcom/dayjs/__mocks__"; +import "@calcom/features/auth/Turnstile"; + +import { Booker } from "../Booker"; +import { useBookerStore } from "../store"; +import type { BookerState } from "../types"; + +// Mock components that we don't want to test +vi.mock("../components/BookEventForm", () => ({ + BookEventForm: ({ + isTimeslotUnavailable, + onCancel, + }: { + isTimeslotUnavailable: boolean; + onCancel: () => void; + }) => { + console.log("BookEventForm Called", { isTimeslotUnavailable, onCancel }); + return ( +
+ Mock Book Event Form + +
+ ); + }, +})); + +vi.mock("../components/BookEventForm/BookFormAsModal", () => ({ + BookFormAsModal: () => { + return
Mock Book Form As Modal
; + }, +})); + +const mockEvent = { + data: { + id: 1, + title: "Test Event", + seatsPerTimeSlot: 1, + seatsShowAvailabilityCount: true, + }, + isSuccess: true, + isPending: false, +}; + +const mockSchedule = { + data: { + slots: { + "2024-01-01": [{ time: "2024-01-01T10:00:00Z" }, { time: "2024-01-01T11:00:00Z" }], + }, + }, + isPending: false, + invalidate: vi.fn(), +}; + +vi.mock("@calcom/atoms/hooks/useIsPlatformBookerEmbed", () => ({ + useIsPlatformBookerEmbed: () => false, +})); + +vi.mock("@calcom/atoms/hooks/useIsPlatform", () => ({ + useIsPlatform: () => false, +})); + +// Update mockStoreState to include all required state +const mockStoreState = { + state: "booking" as BookerState, + setState: vi.fn(), + selectedDate: "2024-01-01", + seatedEventData: {}, + setSeatedEventData: vi.fn(), + tentativeSelectedTimeslots: [], + setTentativeSelectedTimeslots: vi.fn(), + dayCount: 7, + setDayCount: vi.fn(), + setSelectedTimeslot: vi.fn(), + selectedTimeslot: null, + formStep: 0, + setFormStep: vi.fn(), + bookerState: "booking", + setBookerState: vi.fn(), + layout: "default", + setLayout: vi.fn(), +}; + +// Update defaultProps to include missing required props +const defaultProps = { + username: "testuser", + eventSlug: "test-event", + entity: { considerUnpublished: false }, + event: mockEvent, + schedule: mockSchedule, + slots: { + selectedTimeslot: "2024-01-01T10:00:00Z", + setSelectedTimeslot: vi.fn(), + allSelectedTimeslots: ["2024-01-01T10:00:00Z"], + quickAvailabilityChecks: [], + }, + bookerForm: { + key: "form-key", + bookerFormErrorRef: { current: null }, + formEmail: "", + bookingForm: { + watch: vi.fn(), + setValue: vi.fn(), + getValues: vi.fn().mockReturnValue({ responses: {} }), + }, + errors: {}, + }, + bookings: { + handleBookEvent: vi.fn(), + errors: {}, + loadingStates: {}, + expiryTime: 0, + instantVideoMeetingUrl: "", + }, + verifyEmail: { + isEmailVerificationModalVisible: false, + setEmailVerificationModalVisible: vi.fn(), + handleVerifyEmail: vi.fn(), + renderConfirmNotVerifyEmailButtonCond: true, + isVerificationCodeSending: false, + }, + calendars: { + overlayBusyDates: [], + isOverlayCalendarEnabled: false, + connectedCalendars: [], + loadingConnectedCalendar: false, + onToggleCalendar: vi.fn(), + }, + bookerLayout: { + shouldShowFormInDialog: false, + extraDays: 7, + columnViewExtraDays: { current: 7 }, + isMobile: false, + layout: "MONTH_VIEW", + hideEventTypeDetails: false, + isEmbed: false, + bookerLayouts: { enabledLayouts: [] }, + hasDarkBackground: false, + }, + verifyCode: null, + isPlatform: false, + orgBannerUrl: null, + customClassNames: {}, + areInstantMeetingParametersSet: false, + userLocale: "en", + hasValidLicense: true, + isBookingDryRun: false, + renderCaptcha: false, + onConnectNowInstantMeeting: vi.fn(), + onGoBackInstantMeeting: vi.fn(), + onOverlayClickNoCalendar: vi.fn(), + onClickOverlayContinue: vi.fn(), + onOverlaySwitchStateChange: vi.fn(), + extraOptions: {}, + sessionUsername: null, + rescheduleUid: null, + hasSession: false, + isInstantMeeting: false, +}; + +describe("Booker", () => { + beforeEach(() => { + constantsScenarios.set({ + PUBLIC_QUICK_AVAILABILITY_ROLLOUT: 100, + }); + vi.clearAllMocks(); + }); + + it("should render null when in loading state", () => { + useBookerStore.setState({ + ...mockStoreState, + state: "loading", + }); + + const { container } = render(); + expect(container).toBeEmptyDOMElement(); + }); + + it("should render DryRunMessage when in dry run mode", () => { + useBookerStore.setState({ + ...mockStoreState, + state: "selecting_time", + selectedDate: "2024-01-01", + selectedTimeslot: "2024-01-01T10:00:00Z", + tentativeSelectedTimeslots: ["2024-01-01T10:00:00Z"], + }); + + const propsWithDryRun = { + ...defaultProps, + isBookingDryRun: true, + event: { + ...mockEvent, + data: { + ...mockEvent.data, + isDynamic: false, + }, + }, + }; + + render(); + expect(screen.getByTestId("dry-run-message")).toBeInTheDocument(); + }); + + it("should invalidate schedule when cancelling booking form", () => { + const mockInvalidate = vi.fn(); + constantsScenarios.set({ + PUBLIC_INVALIDATE_AVAILABLE_SLOTS_ON_BOOKING_FORM: "true", + }); + const propsWithInvalidate = { + ...defaultProps, + schedule: { + ...mockSchedule, + invalidate: mockInvalidate, + }, + }; + useBookerStore.setState({ + ...mockStoreState, + state: "booking", + }); + + render(); + screen.logTestingPlaygroundURL(); + // Trigger form cancel + const cancelButton = screen.getByRole("button", { name: /cancel/i }); + cancelButton.click(); + + expect(mockInvalidate).toHaveBeenCalled(); + expect(defaultProps.slots.setSelectedTimeslot).toHaveBeenCalledWith(null); + }); + + describe("Schedule and Availability Check", () => { + it("should mark timeslot as unavailable based on quick availability checks", async () => { + const propsWithQuickChecks = { + ...defaultProps, + slots: { + ...defaultProps.slots, + quickAvailabilityChecks: [{ utcStartIso: "2024-01-01T10:00:00Z", status: "unavailable" }], + }, + }; + + useBookerStore.setState({ + ...mockStoreState, + state: "booking", + }); + + render(); + const bookEventForm = screen.getByTestId("book-event-form"); + await expect(bookEventForm).toHaveAttribute("data-unavailable", "true"); + }); + }); +}); diff --git a/packages/features/bookings/Booker/components/OverlayCalendar/__mocks__/OverlayCalendar.tsx b/packages/features/bookings/Booker/components/OverlayCalendar/__mocks__/OverlayCalendar.tsx new file mode 100644 index 0000000000..6aa405031c --- /dev/null +++ b/packages/features/bookings/Booker/components/OverlayCalendar/__mocks__/OverlayCalendar.tsx @@ -0,0 +1,21 @@ +import { vi } from "vitest"; + +const mockOverlayCalendar = vi.fn(() => { + return { + connectedCalendars: [], + overlayBusyDates: [], + onToggleCalendar: vi.fn(), + isOverlayCalendarEnabled: false, + loadingConnectedCalendar: false, + handleClickNoCalendar: vi.fn(), + handleSwitchStateChange: vi.fn(), + handleClickContinue: vi.fn(), + hasSession: false, + }; +}); + +vi.mock("../OverlayCalendar", () => ({ + OverlayCalendar: mockOverlayCalendar, +})); + +export default mockOverlayCalendar; diff --git a/packages/features/bookings/Booker/components/__mocks__/AvailableTimeSlots.tsx b/packages/features/bookings/Booker/components/__mocks__/AvailableTimeSlots.tsx new file mode 100644 index 0000000000..28449479a0 --- /dev/null +++ b/packages/features/bookings/Booker/components/__mocks__/AvailableTimeSlots.tsx @@ -0,0 +1,5 @@ +vi.mock("../AvailableTimeSlots", () => ({ + AvailableTimeSlots: ({ children }: { children: React.ReactNode }) => ( +
{children}
+ ), +})); diff --git a/packages/features/bookings/Booker/components/__mocks__/DatePicker.tsx b/packages/features/bookings/Booker/components/__mocks__/DatePicker.tsx new file mode 100644 index 0000000000..be3b15129a --- /dev/null +++ b/packages/features/bookings/Booker/components/__mocks__/DatePicker.tsx @@ -0,0 +1,3 @@ +vi.mock("../components/DatePicker", () => ({ + DatePicker: () =>
Mock Date Picker
, +})); diff --git a/packages/features/bookings/Booker/components/__mocks__/DryRunMessage.tsx b/packages/features/bookings/Booker/components/__mocks__/DryRunMessage.tsx new file mode 100644 index 0000000000..b5d58bb43f --- /dev/null +++ b/packages/features/bookings/Booker/components/__mocks__/DryRunMessage.tsx @@ -0,0 +1,5 @@ +vi.mock("../DryRunMessage", () => ({ + DryRunMessage: ({ isEmbed }: { isEmbed: boolean }) => ( +
Mock Dry Run Message
+ ), +})); diff --git a/packages/features/bookings/Booker/components/__mocks__/EventMeta.tsx b/packages/features/bookings/Booker/components/__mocks__/EventMeta.tsx new file mode 100644 index 0000000000..c326960df8 --- /dev/null +++ b/packages/features/bookings/Booker/components/__mocks__/EventMeta.tsx @@ -0,0 +1,16 @@ +import { vi } from "vitest"; + +vi.mock("../EventMeta", () => ({ + EventMeta: () => { + return ( +
+

Test Event

+

Test Description

+
+ 30 minutes + Free +
+
+ ); + }, +})); diff --git a/packages/features/bookings/Booker/components/__mocks__/Header.tsx b/packages/features/bookings/Booker/components/__mocks__/Header.tsx new file mode 100644 index 0000000000..ae6e7334cf --- /dev/null +++ b/packages/features/bookings/Booker/components/__mocks__/Header.tsx @@ -0,0 +1,4 @@ +// Mock layout components +vi.mock("../Header", () => ({ + Header: ({ children }: { children: React.ReactNode }) =>
{children}
, +})); diff --git a/packages/features/bookings/Booker/components/__mocks__/LargeCalendar.tsx b/packages/features/bookings/Booker/components/__mocks__/LargeCalendar.tsx new file mode 100644 index 0000000000..00ece154b4 --- /dev/null +++ b/packages/features/bookings/Booker/components/__mocks__/LargeCalendar.tsx @@ -0,0 +1,13 @@ +import { vi } from "vitest"; + +vi.mock("../LargeCalendar", () => ({ + LargeCalendar: ({ extraDays, schedule }: { extraDays: number; schedule: any }) => { + return ( +
+

Test Large Calendar

+

Extra Days: {extraDays}

+

Schedule: {JSON.stringify(schedule)}

+
+ ); + }, +})); diff --git a/packages/features/bookings/Booker/components/__mocks__/Section.tsx b/packages/features/bookings/Booker/components/__mocks__/Section.tsx new file mode 100644 index 0000000000..7c1c364be0 --- /dev/null +++ b/packages/features/bookings/Booker/components/__mocks__/Section.tsx @@ -0,0 +1,22 @@ +vi.mock("../Section", () => { + const BookerSection = ({ + children, + className = "", + area, + }: { + children: React.ReactNode; + className?: string; + area?: string | { default: string; month_view: string }; + }) => { + console.log("BookerSection", { type: children.type, children, className, area }); + return ( +
+ {children} +
+ ); + }; + return { BookerSection }; +}); diff --git a/packages/features/bookings/Booker/components/__mocks__/Unavailable.tsx b/packages/features/bookings/Booker/components/__mocks__/Unavailable.tsx new file mode 100644 index 0000000000..97ef28e6a4 --- /dev/null +++ b/packages/features/bookings/Booker/components/__mocks__/Unavailable.tsx @@ -0,0 +1,3 @@ +vi.mock("../components/Unavailable", () => ({ + NotFound: () =>
Mock Not Found
, +})); diff --git a/packages/lib/__mocks__/constants.ts b/packages/lib/__mocks__/constants.ts index 2f97915477..b7d45d23c3 100644 --- a/packages/lib/__mocks__/constants.ts +++ b/packages/lib/__mocks__/constants.ts @@ -6,6 +6,20 @@ const mockedConstants = { IS_PRODUCTION: false, IS_TEAM_BILLING_ENABLED: false, WEBSITE_URL: "", + PUBLIC_INVALIDATE_AVAILABLE_SLOTS_ON_BOOKING_FORM: true, + CLOUDFLARE_SITE_ID: "test-site-id", + CLOUDFLARE_USE_TURNSTILE_IN_BOOKER: "1", + DEFAULT_LIGHT_BRAND_COLOR: "#292929", + DEFAULT_DARK_BRAND_COLOR: "#fafafa", + CALCOM_VERSION: "0.0.0", + IS_SELF_HOSTED: false, + SEO_IMG_DEFAULT: "https://cal.com/og-image.png", + SEO_IMG_OGIMG: "https://cal.com/og-image-wide.png", + SEO_IMG_LOGO: "https://cal.com/logo.png", + CURRENT_TIMEZONE: "Europe/London", + APP_NAME: "Cal.com", + BOOKER_NUMBER_OF_DAYS_TO_LOAD: 14, + PUBLIC_QUICK_AVAILABILITY_ROLLOUT: 100, } as typeof constants; vi.mock("@calcom/lib/constants", () => { @@ -31,4 +45,11 @@ export const constantsScenarios = { // @ts-ignore mockedConstants.WEBSITE_URL = url; }, + set: (envVariables: Record) => { + Object.entries(envVariables).forEach(([key, value]) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + mockedConstants[key] = value; + }); + }, }; diff --git a/packages/lib/__mocks__/logger.ts b/packages/lib/__mocks__/logger.ts new file mode 100644 index 0000000000..2c5decf19f --- /dev/null +++ b/packages/lib/__mocks__/logger.ts @@ -0,0 +1,16 @@ +import { vi } from "vitest"; + +const mockLogger = { + debug: vi.fn(), + error: vi.fn(), + info: vi.fn(), + log: vi.fn(), + warn: vi.fn(), + getSubLogger: vi.fn(), +}; + +vi.mock("@calcom/lib/logger", () => ({ + default: mockLogger, +})); + +export default mockLogger; diff --git a/packages/lib/__mocks__/next-seo.config.ts b/packages/lib/__mocks__/next-seo.config.ts new file mode 100644 index 0000000000..5f3f751a2e --- /dev/null +++ b/packages/lib/__mocks__/next-seo.config.ts @@ -0,0 +1,17 @@ +vi.mock("@calcom/lib/next-seo.config", () => ({ + default: { + headSeo: { + siteName: "Cal.com", + }, + defaultNextSeo: { + title: "Cal.com", + description: "Scheduling infrastructure for everyone.", + }, + }, + seoConfig: { + headSeo: { + siteName: "Cal.com", + }, + }, + buildSeoMeta: vi.fn().mockReturnValue({}), +})); diff --git a/packages/ui/components/__mocks__/UnpublishedEntity.tsx b/packages/ui/components/__mocks__/UnpublishedEntity.tsx new file mode 100644 index 0000000000..417ad57b6c --- /dev/null +++ b/packages/ui/components/__mocks__/UnpublishedEntity.tsx @@ -0,0 +1,5 @@ +import { vi } from "vitest"; + +vi.mock("../unpublished-entity/UnpublishedEntity", () => ({ + UnpublishedEntity: () =>
Mock Unpublished Entity
, +})); diff --git a/packages/ui/components/test-setup.ts b/packages/ui/components/test-setup.tsx similarity index 73% rename from packages/ui/components/test-setup.ts rename to packages/ui/components/test-setup.tsx index 2150479a20..beb3908a42 100644 --- a/packages/ui/components/test-setup.ts +++ b/packages/ui/components/test-setup.tsx @@ -6,12 +6,33 @@ import { afterEach, expect, vi } from "vitest"; // For next.js webapp compponent that use "preserve" for jsx in tsconfig.json global.React = React; +vi.mock("framer-motion", () => ({ + AnimatePresence: ({ children }: { children: React.ReactNode }) => <>{children}, + LazyMotion: ({ children }: { children: React.ReactNode }) => <>{children}, + m: { + span: ({ children }: { children: React.ReactNode }) => {children}, + div: ({ children }: { children: React.ReactNode }) =>
{children}
, + }, + useReducedMotion: () => false, + useAnimate: () => [null, vi.fn()], +})); + +// Add new mocks +vi.mock("next-seo", () => ({ + NextSeo: () => null, + LogoJsonLd: () => null, +})); + vi.mock("@calcom/features/ee/organizations/hooks", () => ({ useOrgBrandingValues() { return {}; }, })); +vi.mock("react-sticky-box", () => ({ + default: ({ children }: { children: React.ReactNode }) =>
{children}
, +})); + vi.mock("@calcom/features/ee/organizations/context/provider", () => ({ useOrgBranding() { return {}; diff --git a/vitest.workspace.ts b/vitest.workspace.ts index e22b599930..85fc2528a4 100644 --- a/vitest.workspace.ts +++ b/vitest.workspace.ts @@ -110,7 +110,7 @@ const workspaces = packagedEmbedTestsOnly include: ["packages/features/**/*.{test,spec}.tsx"], exclude: ["packages/features/form-builder/**/*", "packages/features/bookings/**/*"], environment: "jsdom", - setupFiles: ["setupVitest.ts", "packages/ui/components/test-setup.ts"], + setupFiles: ["setupVitest.ts", "packages/ui/components/test-setup.tsx"], }, }, @@ -128,7 +128,7 @@ const workspaces = packagedEmbedTestsOnly name: "@calcom/app-store-core", include: ["packages/app-store/*.{test,spec}.[jt]s?(x)"], environment: "jsdom", - setupFiles: ["packages/ui/components/test-setup.ts"], + setupFiles: ["packages/ui/components/test-setup.tsx"], }, }, { @@ -137,7 +137,7 @@ const workspaces = packagedEmbedTestsOnly name: "@calcom/routing-forms", include: ["packages/app-store/routing-forms/**/*.test.tsx"], environment: "jsdom", - setupFiles: ["packages/ui/components/test-setup.ts"], + setupFiles: ["packages/ui/components/test-setup.tsx"], }, }, { @@ -146,7 +146,7 @@ const workspaces = packagedEmbedTestsOnly name: "@calcom/ui", include: ["packages/ui/components/**/*.{test,spec}.[jt]s?(x)"], environment: "jsdom", - setupFiles: ["packages/ui/components/test-setup.ts"], + setupFiles: ["packages/ui/components/test-setup.tsx"], }, }, { @@ -155,7 +155,7 @@ const workspaces = packagedEmbedTestsOnly name: "@calcom/features/form-builder", include: ["packages/features/form-builder/**/*.{test,spec}.[jt]sx"], environment: "jsdom", - setupFiles: ["packages/ui/components/test-setup.ts"], + setupFiles: ["packages/ui/components/test-setup.tsx"], }, }, { @@ -164,7 +164,7 @@ const workspaces = packagedEmbedTestsOnly name: "@calcom/features/bookings", include: ["packages/features/bookings/**/*.{test,spec}.[jt]sx"], environment: "jsdom", - setupFiles: ["packages/ui/components/test-setup.ts"], + setupFiles: ["packages/ui/components/test-setup.tsx"], }, }, { @@ -173,7 +173,7 @@ const workspaces = packagedEmbedTestsOnly name: "@calcom/web/components", include: ["apps/web/components/**/*.{test,spec}.[jt]sx"], environment: "jsdom", - setupFiles: ["packages/ui/components/test-setup.ts"], + setupFiles: ["packages/ui/components/test-setup.tsx"], }, }, {