import "@calcom/ui/__mocks__/ui"; import { TooltipProvider } from "@radix-ui/react-tooltip"; import { render, fireEvent, screen } from "@testing-library/react"; import * as React from "react"; import type { UseFormReturn } from "react-hook-form"; import { FormProvider, useForm } from "react-hook-form"; import { expect } from "vitest"; import { vi } from "vitest"; import { getBookingFieldsWithSystemFields } from "../../../lib/getBookingFields"; import { BookingFields } from "./BookingFields"; // eslint-disable-next-line @typescript-eslint/no-explicit-any type FormMethods = UseFormReturn; // Add tRPC mock before tests vi.mock("@calcom/trpc/react", () => ({ trpc: { viewer: { public: { countryCode: { useQuery: () => ({ data: { countryCode: "US" }, isLoading: false, error: null, }), }, }, }, }, })); const renderComponent = ({ props: props, formDefaultValues, }: { props: Parameters[0]; // eslint-disable-next-line @typescript-eslint/no-explicit-any formDefaultValues?: any; }) => { let formMethods: UseFormReturn | undefined; const Wrapper = ({ children }: { children: React.ReactNode }) => { const form = useForm({ defaultValues: formDefaultValues, }); formMethods = form; return ( {children} ); }; const result = render(, { wrapper: Wrapper }); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return { result, formMethods: formMethods! }; }; describe("BookingFields", () => { it("should correctly render with location fields", () => { const AttendeePhoneNumberOption = { label: "attendee_phone_number", value: "phone", }; const OrganizerLinkOption = { label: "https://google.com", value: "link", }; const locations = [ { type: AttendeePhoneNumberOption.value, }, { link: "https://google.com", type: OrganizerLinkOption.value, displayLocationPublicly: true, }, ]; const { formMethods } = renderComponent({ props: { fields: getBookingFieldsWithSystemFields({ disableGuests: false, bookingFields: [], metadata: null, workflows: [], customInputs: [], }), locations, isDynamicGroupBooking: false, bookingData: null, }, formDefaultValues: {}, }); component.fillName({ value: "John Doe" }); component.fillEmail({ value: "john.doe@example.com" }); component.fillNotes({ value: "This is a note" }); expectScenarios.expectNameToBe({ value: "John Doe", formMethods }); expectScenarios.expectEmailToBe({ value: "john.doe@example.com", formMethods }); expectScenarios.expectNotesToBe({ value: "This is a note", formMethods }); component.fillRadioInputLocation({ label: AttendeePhoneNumberOption.label, inputValue: "+1234567890" }); expectScenarios.expectLocationToBe({ formMethods, label: AttendeePhoneNumberOption.label, toMatch: { formattedValue: "+1 (234) 567-890", value: { optionValue: "+1234567890", value: AttendeePhoneNumberOption.value }, }, }); component.fillRadioInputLocation({ label: OrganizerLinkOption.label }); expectScenarios.expectLocationToBe({ formMethods, label: OrganizerLinkOption.label, toMatch: { formattedValue: "+1 (234) 567-890", value: { optionValue: "", value: OrganizerLinkOption.value }, }, }); }); }); const component = { getName: ({ label = "your_name" }: { label?: string } = {}) => screen.getByRole("textbox", { name: new RegExp(label), }) as HTMLInputElement, getEmail: () => screen.getByRole("textbox", { name: /email/i }) as HTMLInputElement, getLocationRadioOption: ({ label }: { label: string }) => screen.getByRole("radio", { name: new RegExp(label) }) as HTMLInputElement, getLocationRadioInput: ({ placeholder }: { placeholder: string }) => screen.getByPlaceholderText(placeholder) as HTMLInputElement, getNotes: () => screen.getByRole("textbox", { name: /additional_notes/i }) as HTMLInputElement, getGuests: () => screen.getByLabelText("guests"), fillName: ({ value }: { value: string }) => { fireEvent.change(component.getName(), { target: { value } }); }, fillEmail: ({ value }: { value: string }) => { fireEvent.change(component.getEmail(), { target: { value } }); }, fillRadioInputLocation: ({ label, inputValue }: { label: string; inputValue?: string }) => { fireEvent.click(component.getLocationRadioOption({ label })); if (inputValue) { let placeholder = label; if (label === "attendee_phone_number") { placeholder = "enter_phone_number"; } else { // radioInput doesn't have a label, so we need to identify by placeholder throw new Error("Tell me how to identify the placeholder for this location input"); } fireEvent.change(component.getLocationRadioInput({ placeholder }), { target: { value: inputValue }, }); } }, fillNotes: ({ value }: { value: string }) => { fireEvent.change(component.getNotes(), { target: { value } }); }, }; const expectScenarios = { expectNameToBe: ({ value, formMethods }: { value: string; formMethods: FormMethods }) => { expect(component.getName().value).toEqual(value); expect(formMethods.getValues("responses.name")).toEqual(value); }, expectEmailToBe: ({ value, formMethods }: { value: string; formMethods: FormMethods }) => { expect(component.getEmail().value).toEqual(value); expect(formMethods.getValues("responses.email")).toEqual(value); }, expectLocationToBe: ({ formMethods, label, toMatch: { formattedValue, value }, }: { label: string; toMatch: { formattedValue?: string; value: { optionValue: string; value: string; }; }; formMethods: FormMethods; }) => { expect(component.getLocationRadioOption({ label }).checked).toBe(true); if (value.optionValue) { expect(component.getLocationRadioInput({ placeholder: "enter_phone_number" }).value).toEqual( formattedValue ); } expect(formMethods.getValues("responses.location")).toEqual(value); }, expectNotesToBe: ({ value, formMethods }: { value: string; formMethods: FormMethods }) => { expect(component.getNotes().value).toEqual(value); expect(formMethods.getValues("responses.notes")).toEqual(value); }, };