Skip to content

Commit

Permalink
test(FormBuilder): add tests to FormBuilder elements
Browse files Browse the repository at this point in the history
  • Loading branch information
ribeirojose committed Apr 28, 2024
1 parent 8f93804 commit d980c85
Show file tree
Hide file tree
Showing 26 changed files with 744 additions and 21 deletions.
1 change: 1 addition & 0 deletions src/components/FormBuilder/fields/DatePickerInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const DatePickerInput = withConditional<DatePickerInputProps>(
control={form.control}
name={field.name}
rules={field.required ? { required: true } : undefined}
defaultValue={field.defaultValue}
render={({ field: formField }) => (
<FormItem className="flex flex-col">
<FormLabel tooltip={field.tooltip}>{field.label}</FormLabel>
Expand Down
13 changes: 6 additions & 7 deletions src/components/FormBuilder/fields/FieldArray.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,7 @@ export const FieldArray = withConditional<FieldArrayFieldProps>(
<DragDropContext onDragEnd={handleDrag}>
<ul>
<StrictModeDroppable droppableId={`${field.name}-items`}>
{/* eslint-disable-next-line no-shadow, @typescript-eslint/no-unused-vars */}
{(provided, snapshot) => (
{(provided) => (
<div {...provided.droppableProps} ref={provided.innerRef}>
{fields.map((rhfField, index) => {
// @ts-expect-error
Expand All @@ -139,11 +138,10 @@ export const FieldArray = withConditional<FieldArrayFieldProps>(
draggableId={`item-${index}`}
index={index}
>
{/* eslint-disable-next-line no-shadow, @typescript-eslint/no-unused-vars */}
{(provided, snapshot) => (
{(innerProvided) => (
<li
ref={provided.innerRef}
{...provided.draggableProps}
ref={innerProvided.innerRef}
{...innerProvided.draggableProps}
className="mb-3"
>
<div
Expand All @@ -152,7 +150,7 @@ export const FieldArray = withConditional<FieldArrayFieldProps>(
{field.hasSequence && (
<div
className="flex h-full w-6 flex-col justify-center"
{...provided.dragHandleProps}
{...innerProvided.dragHandleProps}
>
<MoveIcon className="size-6 self-center" />
</div>
Expand All @@ -167,6 +165,7 @@ export const FieldArray = withConditional<FieldArrayFieldProps>(
// eslint-disable-next-line jsx-a11y/control-has-associated-label
<button
type="button"
data-testid="remove-button"
onClick={() => handleRemove(Number(index))}
className="mt-4"
>
Expand Down
6 changes: 3 additions & 3 deletions src/components/FormBuilder/fields/HiddenField.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { FormControl, FormField } from "#/components/ui/Form";
import { FormField, FormItem } from "#/components/ui/Form";

import { withConditional } from "../fields";

Expand All @@ -9,9 +9,9 @@ export const HiddenField = withConditional(({ form, field }) => (
name={field.name}
defaultValue={field.value}
render={({ field: formField }) => (
<FormControl>
<FormItem>
<input type="hidden" {...formField} />
</FormControl>
</FormItem>
)}
/>
));
1 change: 1 addition & 0 deletions src/components/FormBuilder/fields/InputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const InputField = withConditional<InputFieldProps>(
}
: undefined
}
defaultValue={field.defaultValue}
render={({ field: formField }) => (
<FormItem className="w-full">
<FormLabel tooltip={field.tooltip}>{field.label}</FormLabel>
Expand Down
28 changes: 28 additions & 0 deletions tests/components/FormBuilder/CheckboxField.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { describe, it, expect } from "vitest";
import { screen, fireEvent } from "@testing-library/react";

import { renderFormField } from "tests/helpers/renderFormField";
import { CheckboxField, CheckboxFieldProps } from "#/components";

describe("CheckboxField", () => {
const field: CheckboxFieldProps = {
type: "checkbox",
name: "test",
value: "",
label: "Test Checkbox",
};
it("renders a checkbox element", () => {
renderFormField(CheckboxField, field);

const checkboxElement = screen.getByRole("checkbox");
expect(checkboxElement).toBeInTheDocument();
});

it("updates the form state correctly when interacted with", () => {
const { form } = renderFormField(CheckboxField, field);

const checkboxElement = screen.getByRole("checkbox");
fireEvent.click(checkboxElement);
expect(form.getValues("test")).toBe(true);
});
});
32 changes: 32 additions & 0 deletions tests/components/FormBuilder/DatePickerInput.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { vi, describe, it, expect } from "vitest";
import { screen, fireEvent } from "@testing-library/react";
import { renderFormField } from "tests/helpers/renderFormField";
import { DatePickerInput } from "#/components";

describe("DatePickerInput", () => {
const mockDate = new Date(2022, 0, 1);
const field = {
type: "date",
name: "test",
defaultValue: "",
};

it("renders a date picker input", () => {
renderFormField(DatePickerInput, field);

const datePickerElement = screen.getByText("Pick a date");
expect(datePickerElement).toBeInTheDocument();
});

it("updates the form state correctly when a date is selected", () => {
vi.setSystemTime(mockDate);
const { form } = renderFormField(DatePickerInput, field);

const datePickerElement = screen.getByText("Pick a date");
fireEvent.click(datePickerElement);
const dateElement = screen.getByText("10");
fireEvent.click(dateElement);

expect(form.getValues("test")).toStrictEqual(new Date(2022, 0, 10));
});
});
53 changes: 53 additions & 0 deletions tests/components/FormBuilder/FieldArray.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { describe, it, expect } from "vitest";
import { screen, fireEvent } from "@testing-library/react";
import { renderFormField } from "tests/helpers/renderFormField";
import { FieldArray } from "#/components";

describe("FieldArray", () => {
it("renders an 'Add' button", () => {
const field = {
type: "field_array",
name: "test",
fields: [],
hasSequence: false,
};

renderFormField(FieldArray, field);
const addButton = screen.getByText("Add");
expect(addButton).toBeInTheDocument();
});

it("adds a new field when the 'Add' button is clicked", () => {
const field = {
type: "field_array",
name: "test",
label: "Test",
defaultValues: { name: "" },
fields: [{ type: "input", name: "name" }],
hasSequence: false,
};
const { form } = renderFormField(FieldArray, field);

const addButton = screen.getByText(`Add ${field.label}`);
fireEvent.click(addButton);
expect(form.getValues(field.name)).toHaveLength(1);
});

// it("removes a field when the remove button is clicked", () => {
// const field = {
// type: "field_array",
// name: "test",
// defaultValues: { name: "" },
// fields: [{ type: "input", name: "name" }],
// hasSequence: false,
// remove: true,
// };
// const { result } = renderHook(() =>
// useForm({ defaultValues: { [field.name]: [{ name: "John" }] } })
// );
// render(<TestForm field={field} form={result.current} />);
// const removeButton = screen.getByTestId("remove-button");
// fireEvent.click(removeButton);
// expect(result.current.getValues(field.name)).toHaveLength(0);
// });
});
29 changes: 29 additions & 0 deletions tests/components/FormBuilder/FileUploadField.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { describe, it, expect } from "vitest";
import { screen } from "@testing-library/react";
import { renderFormField } from "tests/helpers/renderFormField";
import { FileUploadField } from "#/components";

describe("FileUploadField", () => {
it("renders an upload button", () => {
const field = { type: "file", name: "test", mode: "file" };

renderFormField(FileUploadField, field);

const uploadButton = screen.getByText("Upload a file");
expect(uploadButton).toBeInTheDocument();
});

// it("updates the form state when a file is uploaded", async () => {
// const field = { type: "file", name: "test", mode: "file" };
// const { result } = renderHook(() => useForm());
// render(<TestForm field={field} form={result.current} />);
// const file = new File(["test"], "test.txt", { type: "text/plain" });
// const inputElement = screen.getByRole("button", { name: "Upload a file" });
// Object.defineProperty(inputElement, "files", {
// value: [file],
// });
// fireEvent.change(inputElement);

// expect(result.current.getValues(field.name)).toBeInstanceOf(File);
// });
});
40 changes: 40 additions & 0 deletions tests/components/FormBuilder/FormField.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// FormField.test.tsx
import React from "react";
import { describe, it, expect, vi } from "vitest";
import { render, renderHook, screen } from "@testing-library/react";
import { FormProvider, useForm } from "react-hook-form";
import { FormField } from "#/components";

describe("FormField", () => {
const renderFormField = (props) => {
const { result } = renderHook(() => useForm());
return (
<FormProvider {...result.current}>
<FormField {...props} />
</FormProvider>
);
};

it("renders the appropriate field component based on the render prop", () => {
render(
renderFormField({
name: "test",
render: ({ field }) => <input {...field} placeholder="Enter text" />,
})
);
const inputElement = screen.getByPlaceholderText("Enter text");
expect(inputElement).toBeInTheDocument();
});

it("passes the correct props to the render function", () => {
const renderMock = vi.fn();
render(renderFormField({ name: "test", render: renderMock }));
expect(renderMock).toHaveBeenCalledWith(
expect.objectContaining({
field: expect.any(Object),
fieldState: expect.any(Object),
formState: expect.any(Object),
})
);
});
});
41 changes: 41 additions & 0 deletions tests/components/FormBuilder/FormFieldProvider.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// import * as React from "react";
// import { describe, it, expect } from "vitest";
// import { render, screen, renderHook } from "@testing-library/react";
// import {
// FormFieldProvider,
// useFormFieldState,
// useFormFieldUpdater,
// } from "#/components";

// describe("FormFieldProvider", () => {
// it("correctly initializes the field state with the provided name", () => {
// render(
// <FormFieldProvider
// name="test"
// render={({ field }) => <div {...field} data-testid="child" />}
// />
// );
// const childElement = screen.getByTestId("child");
// expect(childElement).toBeInTheDocument();
// });

// it("provides the field state and updater function to its children", () => {
// const { result } = renderHook(
// () => {
// const fieldState = useFormFieldState();
// const setFieldState = useFormFieldUpdater();
// return { fieldState, setFieldState };
// },
// {
// wrapper: ({ children }) => (
// <FormFieldProvider
// name="test"
// render={({ field }) => <div>{children}</div>}
// />
// ),
// }
// );
// expect(result.current.fieldState.name).toBe("test");
// expect(typeof result.current.setFieldState).toBe("function");
// });
// });
15 changes: 15 additions & 0 deletions tests/components/FormBuilder/HiddenField.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { describe, it, expect } from "vitest";
import { HiddenField } from "#/components";
import { renderFormField } from "../../../tests/helpers/renderFormField";

describe("HiddenField", () => {
it("renders a hidden input field", () => {
const { form } = renderFormField(HiddenField, {
type: "hidden",
name: "test",
value: "hiddenValue",
});
const hiddenInput = form.getValues("test");
expect(hiddenInput).toBe("hiddenValue");
});
});
35 changes: 35 additions & 0 deletions tests/components/FormBuilder/InputField.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { describe, it, expect } from "vitest";
import { screen, fireEvent } from "@testing-library/react";
import { renderFormField } from "tests/helpers/renderFormField";
import { InputField } from "#/components";

describe("InputField", () => {
it("renders an input element", () => {
const field = { type: "input", name: "test", value: "" };
renderFormField(InputField, field);
const inputElement = screen.getByRole("textbox");
expect(inputElement).toBeInTheDocument();
});

// it("applies the appropriate validation rules", () => {
// const field = { type: "input", name: "test", required: true };
// render(<TestForm field={field} />);
// const inputElement = screen.getByRole("textbox");
// fireEvent.change(inputElement, { target: { value: "" } });
// expect(inputElement).toBeInvalid();
// });

it("updates the form state correctly when interacted with", () => {
const field = {
type: "input",
name: "test",
value: "",
defaultValue: "",
mode: "text",
} as const;
const { form } = renderFormField(InputField, field);
const inputElement = screen.getByRole("textbox");
fireEvent.change(inputElement, { target: { value: "Test value" } });
expect(form.getValues("test")).toBe("Test value");
});
});
34 changes: 34 additions & 0 deletions tests/components/FormBuilder/MultiSelectCheckboxesField.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { describe, it, expect } from "vitest";
import { screen, fireEvent } from "@testing-library/react";
import { renderFormField } from "tests/helpers/renderFormField";
import { MultiSelectCheckboxes } from "#/components";

describe("MultiSelectCheckboxes", () => {
const field = {
type: "multi_select_checkbox",
name: "test",
options: [
{ value: "option1", label: "Option 1" },
{ value: "option2", label: "Option 2" },
],
};

it("renders checkboxes for each option", () => {
renderFormField(MultiSelectCheckboxes, field);
const checkbox1 = screen.getByLabelText("Option 1");
const checkbox2 = screen.getByLabelText("Option 2");
expect(checkbox1).toBeInTheDocument();
expect(checkbox2).toBeInTheDocument();
});

it("updates the form state when checkboxes are checked/unchecked", () => {
const { form } = renderFormField(MultiSelectCheckboxes, field);
const checkbox1 = screen.getByLabelText("Option 1");
const checkbox2 = screen.getByLabelText("Option 2");
fireEvent.click(checkbox1);
fireEvent.click(checkbox2);
expect(form.getValues(field.name)).toEqual(["option1", "option2"]);
fireEvent.click(checkbox1);
expect(form.getValues(field.name)).toEqual(["option2"]);
});
});
Loading

0 comments on commit d980c85

Please sign in to comment.