Files
calendar/packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx
T

202 lines
6.6 KiB
TypeScript

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<any>;
// 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<typeof BookingFields>[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 (
<TooltipProvider>
<FormProvider {...form}>{children}</FormProvider>
</TooltipProvider>
);
};
const result = render(<BookingFields {...props} />, { 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);
},
};