+1




![coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>](/assets/img/avatar_default.png)




Anwar Sadath
GitHub
Omar López
amrit
coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Kartik Saini
Anik Dhabal Babu
Devanshu Sharma
Benny Joo
Peer Richelsen
Volnei Munhoz
55e6682832
* feat: Addons to bookings * Add tests * Add tests * Fix price field not shown immediately after enabling payment for an event * Add support for all currencies in addons and fix type errors * Address review comments * Add tests to cover all input types * Address cubic-dev-ai comments * Remove openapi.json from git tracking * Revert changes * Revert unrelated linter/formatter changes * Address cubic-dev-ai comments * Addres cubic-dev-ai comment * Update to use test id instead of hardcoded label Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Address coderabbits review comments * Fix failing unit test * some fixes... * Fix tests * Fix import * Move handlePayment test file to appropriate location * Fix test --------- Co-authored-by: Omar López <zomars@me.com> Co-authored-by: amrit <iamamrit27@gmail.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Kartik Saini <41051387+kart1ka@users.noreply.github.com> Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com> Co-authored-by: Devanshu Sharma <devanshusharma658@gmail.com> Co-authored-by: Benny Joo <sldisek783@gmail.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: Volnei Munhoz <volnei.munhoz@gmail.com>
275 lines
8.5 KiB
TypeScript
275 lines
8.5 KiB
TypeScript
import { TooltipProvider } from "@radix-ui/react-tooltip";
|
|
import { render } from "@testing-library/react";
|
|
import type { ReactNode } from "react";
|
|
import * as React from "react";
|
|
import { FormProvider, useForm } from "react-hook-form";
|
|
import { vi } from "vitest";
|
|
|
|
import { FormBuilder } from "./FormBuilder";
|
|
import {
|
|
mockProps,
|
|
verifier,
|
|
setMockIntersectionObserver,
|
|
setMockMatchMedia,
|
|
pageObject,
|
|
expectScenario,
|
|
getLocationBookingField,
|
|
} from "./testUtils";
|
|
|
|
vi.mock("@formkit/auto-animate/react", () => ({
|
|
useAutoAnimate: () => [null],
|
|
}));
|
|
|
|
vi.mock("next/navigation", async (importOriginal) => {
|
|
const actual = await importOriginal<typeof import("next/navigation")>();
|
|
return {
|
|
...actual,
|
|
useRouter: vi.fn(() => ({
|
|
push: vi.fn(() => {
|
|
return;
|
|
}),
|
|
})),
|
|
};
|
|
});
|
|
|
|
const renderComponent = ({
|
|
formBuilderProps: formBuilderProps,
|
|
formDefaultValues: formDefaultValues,
|
|
}: {
|
|
formBuilderProps: Parameters<typeof FormBuilder>[0];
|
|
formDefaultValues;
|
|
}) => {
|
|
const Wrapper = ({ children }: { children: ReactNode }) => {
|
|
const form = useForm({
|
|
defaultValues: formDefaultValues,
|
|
});
|
|
return (
|
|
<TooltipProvider>
|
|
<FormProvider {...form}>{children}</FormProvider>
|
|
</TooltipProvider>
|
|
);
|
|
};
|
|
|
|
return render(<FormBuilder {...formBuilderProps} />, { wrapper: Wrapper });
|
|
};
|
|
|
|
describe("FormBuilder", () => {
|
|
beforeAll(() => {
|
|
setMockMatchMedia();
|
|
setMockIntersectionObserver();
|
|
});
|
|
|
|
describe("Basic Tests", () => {
|
|
const fieldTypes = [
|
|
{ fieldType: "email", label: "Email Field" },
|
|
{ fieldType: "phone", label: "Phone Field" },
|
|
{ fieldType: "address", label: "Address Field" },
|
|
{ fieldType: "text", label: "Short Text Field" },
|
|
{ fieldType: "number", label: "Number Field" },
|
|
{ fieldType: "textarea", label: "LongText Field" },
|
|
{ fieldType: "select", label: "Select Field" },
|
|
{ fieldType: "multiselect", label: "MultiSelect Field" },
|
|
{ fieldType: "multiemail", label: "Multiple Emails Field" },
|
|
{ fieldType: "checkbox", label: "CheckBox Group Field" },
|
|
{ fieldType: "radio", label: "Radio Group Field" },
|
|
{ fieldType: "boolean", label: "Checkbox Field" },
|
|
];
|
|
beforeEach(() => {
|
|
renderComponent({ formBuilderProps: mockProps, formDefaultValues: {} });
|
|
});
|
|
|
|
for (const { fieldType, label } of fieldTypes) {
|
|
it(`Should add new field of type ${fieldType} `, async () => {
|
|
const defaultIdentifier = `${fieldType}-id`;
|
|
const newIdentifier = `${defaultIdentifier}-edited`;
|
|
|
|
await verifier.verifyFieldAddition({
|
|
fieldType,
|
|
identifier: defaultIdentifier,
|
|
label,
|
|
});
|
|
|
|
await verifier.verifyIdentifierChange({
|
|
newIdentifier: newIdentifier,
|
|
existingIdentifier: defaultIdentifier,
|
|
});
|
|
|
|
await verifier.verifyThatFieldCanBeMarkedOptional({
|
|
identifier: newIdentifier,
|
|
});
|
|
|
|
await verifier.verifyFieldToggle({ identifier: newIdentifier });
|
|
|
|
await verifier.verifyFieldDeletion({ identifier: newIdentifier });
|
|
});
|
|
}
|
|
});
|
|
|
|
describe("radioInput type field with options available in dataStore", () => {
|
|
test('Should add new field of type "radioInput" and select option from dataStore', async () => {
|
|
const field = {
|
|
identifier: "location",
|
|
type: "radioInput",
|
|
};
|
|
renderComponent({
|
|
formBuilderProps: {
|
|
...mockProps,
|
|
dataStore: {
|
|
options: {
|
|
locations: {
|
|
value: [
|
|
{
|
|
label: "Attendee Phone",
|
|
value: "phone",
|
|
inputPlaceholder: "Phone Number",
|
|
},
|
|
],
|
|
source: { label: "Location" },
|
|
},
|
|
},
|
|
},
|
|
// @typescript-eslint/no-explicit-any
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
shouldConsiderRequired: (field: any) => {
|
|
return field.name === "location" ? true : false;
|
|
},
|
|
},
|
|
formDefaultValues: {
|
|
fields: [getLocationBookingField()],
|
|
},
|
|
});
|
|
|
|
// editable:'system' field can't be deleted
|
|
expectScenario.toNotHaveDeleteButton({ identifier: field.identifier });
|
|
// editable:'system' field can't be toggled
|
|
expectScenario.toNotHaveToggleButton({ identifier: field.identifier });
|
|
expectScenario.toHaveSourceBadge({ identifier: field.identifier, sourceLabel: "1 Location" });
|
|
expectScenario.toHaveRequiredBadge({ identifier: field.identifier });
|
|
|
|
const newFieldDialog = pageObject.openAddFieldDialog();
|
|
|
|
// radioInput type field isn't selectable by the user.
|
|
expect(
|
|
pageObject.dialog.fieldTypeDropdown.queryOptionForFieldType({
|
|
dialog: newFieldDialog,
|
|
fieldType: "radioInput",
|
|
})
|
|
).toBeNull();
|
|
|
|
pageObject.dialog.close({ dialog: newFieldDialog });
|
|
|
|
const dialog = pageObject.openEditFieldDialog({ identifier: field.identifier });
|
|
|
|
expectScenario.toHaveFieldTypeDropdownDisabled({ dialog });
|
|
expectScenario.toHaveIdentifierChangeDisabled({ dialog });
|
|
expectScenario.toHaveRequirablityToggleDisabled({ dialog });
|
|
expectScenario.toHaveLabelChangeAllowed({ dialog });
|
|
expect(pageObject.dialog.isFieldShowingAsRequired({ dialog })).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("Addon Fields Tests", () => {
|
|
beforeEach(() => {
|
|
renderComponent({
|
|
formBuilderProps: {
|
|
...mockProps,
|
|
showPriceField: true,
|
|
},
|
|
formDefaultValues: {},
|
|
});
|
|
});
|
|
|
|
it("Should add number field with price", async () => {
|
|
const identifier = "quantity-addon";
|
|
const price = 10;
|
|
await verifier.verifyFieldAddition({
|
|
fieldType: "number",
|
|
identifier,
|
|
label: "Quantity",
|
|
price,
|
|
});
|
|
|
|
pageObject.openEditFieldDialog({ identifier });
|
|
await expectScenario.toHavePriceField({ identifier, price });
|
|
});
|
|
|
|
it("Should add boolean field with price", async () => {
|
|
const identifier = "extra-service-addon";
|
|
const price = 15;
|
|
await verifier.verifyFieldAddition({
|
|
fieldType: "boolean",
|
|
identifier,
|
|
label: "Extra Service",
|
|
price,
|
|
});
|
|
|
|
pageObject.openEditFieldDialog({ identifier });
|
|
await expectScenario.toHavePriceField({ identifier, price });
|
|
});
|
|
|
|
it("Should add select field with price and options", async () => {
|
|
const identifier = "meal-selection";
|
|
await verifier.verifyFieldAddition({
|
|
fieldType: "select",
|
|
identifier,
|
|
label: "Meal Selection",
|
|
options: [
|
|
{ label: "Vegetarian", value: "veg", price: 20 },
|
|
{ label: "Non-Vegetarian", value: "non-veg", price: 25 },
|
|
],
|
|
});
|
|
|
|
|
|
verifier.verifyOptionPrices({ identifier, prices: [20, 25] });
|
|
});
|
|
|
|
it("Should add multiselect field with price and options", async () => {
|
|
const identifier = "add-ons";
|
|
await verifier.verifyFieldAddition({
|
|
fieldType: "multiselect",
|
|
identifier,
|
|
label: "Add-ons",
|
|
options: [
|
|
{ label: "WiFi", value: "wifi", price: 10 },
|
|
{ label: "Breakfast", value: "breakfast", price: 15 },
|
|
{ label: "Parking", value: "parking", price: 20 },
|
|
],
|
|
});
|
|
|
|
verifier.verifyOptionPrices({ identifier, prices: [10, 15, 20] });
|
|
});
|
|
|
|
it("Should add checkbox group field with price and options", async () => {
|
|
const identifier = "amenities";
|
|
await verifier.verifyFieldAddition({
|
|
fieldType: "checkbox",
|
|
identifier,
|
|
label: "Amenities",
|
|
options: [
|
|
{ label: "Pool Access", value: "pool", price: 15 },
|
|
{ label: "Gym Access", value: "gym", price: 20 },
|
|
{ label: "Spa Access", value: "spa", price: 25 },
|
|
],
|
|
});
|
|
|
|
verifier.verifyOptionPrices({ identifier, prices: [15, 20, 25] });
|
|
});
|
|
|
|
it("Should add radio group field with price and options", async () => {
|
|
const identifier = "room-type";
|
|
await verifier.verifyFieldAddition({
|
|
fieldType: "radio",
|
|
identifier,
|
|
label: "Room Type",
|
|
options: [
|
|
{ label: "Standard", value: "standard", price: 50 },
|
|
{ label: "Deluxe", value: "deluxe", price: 75 },
|
|
{ label: "Suite", value: "suite", price: 100 },
|
|
],
|
|
});
|
|
|
|
verifier.verifyOptionPrices({ identifier, prices: [50, 75, 100] });
|
|
});
|
|
});
|
|
});
|