diff --git a/packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx b/packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx index a2741bf7625b3e..2b355232a47730 100644 --- a/packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx +++ b/packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx @@ -1,34 +1,64 @@ import { TooltipProvider } from "@radix-ui/react-tooltip"; -import { render, screen } from "@testing-library/react"; +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 { getBookingFieldsWithSystemFields } from "../../../lib/getBookingFields"; import { BookingFields } from "./BookingFields"; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type FormMethods = UseFormReturn; + 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} ); }; - return render(, { wrapper: Wrapper }); + const result = render(, { wrapper: Wrapper }); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return { result, formMethods: formMethods! }; }; -describe("FormBuilderField", () => { - it("basic test", () => { - renderComponent({ +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, @@ -37,22 +67,115 @@ describe("FormBuilderField", () => { workflows: [], customInputs: [], }), - locations: [ - { - type: "phone", - }, - { - link: "https://google.com", - type: "link", - displayLocationPublicly: true, - }, - ], + locations, isDynamicGroupBooking: false, bookingData: null, }, formDefaultValues: {}, }); - screen.getByText("email_address"); - screen.logTestingPlaygroundURL(); + + 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); + }, +}; diff --git a/packages/features/bookings/Booker/components/BookEventForm/BookingFields.tsx b/packages/features/bookings/Booker/components/BookEventForm/BookingFields.tsx index ca3913c6826d04..8be7c1bf18a565 100644 --- a/packages/features/bookings/Booker/components/BookEventForm/BookingFields.tsx +++ b/packages/features/bookings/Booker/components/BookEventForm/BookingFields.tsx @@ -99,7 +99,6 @@ export const BookingFields = ({ // TODO: Instead of `getLocationOptionsForSelect` options should be retrieved from dataStore[field.getOptionsAt]. It would make it agnostic of the `name` of the field. const options = getLocationOptionsForSelect(locations, t); - console.log({ options }); options.forEach((option) => { const optionInput = optionsInputs[option.value as keyof typeof optionsInputs]; if (optionInput) { @@ -133,7 +132,6 @@ export const BookingFields = ({ }; }); } - console.log({ field }); return (