Skip to content

Commit

Permalink
Clean up code, improve test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
clement-faure committed Apr 29, 2021
1 parent 961daf2 commit eb672fc
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 65 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ type MuiRhfFormField = {
props?: any;
type?: keyof MuiRhfFieldComponentMap;
gridProps?: Pick<GridProps, "xs" | "sm" | "md" | "lg" | "xl">;
condition?: MuiRhfFormFieldCondition; // Union of conditions
conditions?: MuiRhfFormFieldCondition; // Intersection of conditions
conditionalProps?: MuiRhfFormFieldConditionalProps; // Props applied when condition is satisfied
hideCondition?: MuiRhfFormFieldHideConditions; // Union of conditions, if true, field will be hidden
hideConditions?: MuiRhfFormFieldHideConditions; // Intersection of conditions, if true, field will be hidden
conditionalProps?: MuiRhfFormFieldConditionalProps; // Extra props applied depending on other form fields values
};
```

Expand Down
15 changes: 4 additions & 11 deletions src/components/MuiRhfAutocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,18 @@ import * as React from "react";

import { Controller } from "react-hook-form";

import { TextField, TextFieldProps } from "@material-ui/core";
import { TextField } from "@material-ui/core";
import { Autocomplete } from "@material-ui/lab";

import { MuiRhfFieldProps } from "~/models/fields";

type MuiRhfAutocompleteProps = MuiRhfFieldProps & {
defaultValue?: unknown;
textField?: Omit<TextFieldProps, "onChange">;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
autocomplete?: any;
};
import { MuiRhfAutocompleteProps } from "~/models/fields";

const MuiRhfAutocomplete: React.FC<MuiRhfAutocompleteProps> = ({
control,
errors,
name,
defaultValue,
textField: textFieldProps,
autocomplete: autocompleteProps,
textFieldProps,
autocompleteProps,
}) => (
<Controller
name={name}
Expand Down
15 changes: 3 additions & 12 deletions src/components/MuiRhfAutocompleteMultiple.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
import * as React from "react";

import { TextFieldProps } from "@material-ui/core";

import { MuiRhfFieldProps } from "~/models/fields";
import { MuiRhfAutocompleteProps } from "~/models/fields";

import MuiRhfAutocomplete from "./MuiRhfAutocomplete";

type MuiRhfAutocompleteProps = MuiRhfFieldProps & {
defaultValue?: unknown;
textField?: Omit<TextFieldProps, "onChange">;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
autocomplete?: any;
};

const MuiRhfAutocompleteMultiple: React.FC<MuiRhfAutocompleteProps> = ({
defaultValue = [],
autocomplete: autocompleteProps = {},
autocompleteProps = {},
...rest
}) => (
<MuiRhfAutocomplete
{...rest}
autocomplete={{ ...autocompleteProps, multiple: true }}
autocompleteProps={{ ...autocompleteProps, multiple: true }}
defaultValue={defaultValue}
/>
);
Expand Down
15 changes: 3 additions & 12 deletions src/components/MuiRhfAutocompleteSingle.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
import * as React from "react";

import { TextFieldProps } from "@material-ui/core";

import { MuiRhfFieldProps } from "~/models/fields";
import { MuiRhfAutocompleteProps } from "~/models/fields";

import MuiRhfAutocomplete from "./MuiRhfAutocomplete";

type MuiRhfAutocompleteProps = MuiRhfFieldProps & {
defaultValue?: unknown;
textField?: Omit<TextFieldProps, "onChange">;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
autocomplete?: any;
};

const MuiRhfAutocompleteSingle: React.FC<MuiRhfAutocompleteProps> = ({
defaultValue = null,
autocomplete: autocompleteProps = {},
autocompleteProps = {},
...rest
}) => (
<MuiRhfAutocomplete
{...rest}
autocomplete={{ ...autocompleteProps, multiple: false }}
autocompleteProps={{ ...autocompleteProps, multiple: false }}
defaultValue={defaultValue}
/>
);
Expand Down
36 changes: 18 additions & 18 deletions src/components/MuiRhfForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ const MuiRhfForm: React.FC<MuiRhfFormProps> = ({
props = {},
gridProps = {},
type = "textField",
condition,
conditions,
hideCondition,
hideConditions,
conditionalProps,
}) => {
// Initialize dynamic props based on watched values
Expand All @@ -52,21 +52,21 @@ const MuiRhfForm: React.FC<MuiRhfFormProps> = ({
MuiRhfTextField; //fallback to textField in case not valid type

if (watch) {
// Union will be used in condition keys
if (condition) {
// Union will be used in hideCondition keys
if (hideCondition) {
let conditionHidden = true;

// Retrieve conditions keys
const conditionKeys = Object.keys(condition);
// Retrieve hideConditions keys
const conditionKeys = Object.keys(hideCondition);

// Retrieve watched values
const conditionWatchedValues = watch(conditionKeys);

// Check conditions, we are actually doing an union of conditions
// If at least one condition has been satisfied, display
// Check hideConditions, we are actually doing an union of hideConditions
// If at least one hideCondition has been satisfied, display
conditionKeys.forEach((conditionKey) => {
if (
condition[conditionKey](
hideCondition[conditionKey](
conditionWatchedValues[conditionKey]
)
) {
Expand All @@ -79,21 +79,21 @@ const MuiRhfForm: React.FC<MuiRhfFormProps> = ({
}
}

// Intersection will be used in conditions keys
if (conditions) {
// Intersection will be used in hideConditions keys
if (hideConditions) {
let conditionsHidden = false;

// Retrieve conditions keys
const conditionsKeys = Object.keys(conditions);
// Retrieve hideConditions keys
const conditionsKeys = Object.keys(hideConditions);

// Retrieve watched values
const conditionsWatchedValues = watch(conditionsKeys);

// Check conditions, we are actually doing an union of conditions
// All condition needs to be satisfied to display the field
// Check hideConditions, we are actually doing an union of hideConditions
// All hideCondition needs to be satisfied to display the field
conditionsKeys.forEach((conditionsKey) => {
if (
!conditions[conditionsKey](
!hideConditions[conditionsKey](
conditionsWatchedValues[conditionsKey]
)
) {
Expand All @@ -107,13 +107,13 @@ const MuiRhfForm: React.FC<MuiRhfFormProps> = ({
}

if (conditionalProps) {
// Retrieve conditions keys
// Retrieve hideConditions keys
const conditionalKeys = Object.keys(conditionalProps);

// Retrieve watched values
const conditionalWatchedValues = watch(conditionalKeys);

// Check conditions
// Check hideConditions
conditionalKeys.forEach((conditionalKey) => {
const [path, customCondition] = conditionalProps[
conditionalKey
Expand Down
2 changes: 1 addition & 1 deletion src/components/MuiRhfSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const MuiRhfSelect: React.FC<MuiRhfSelectProps> = ({
label,
defaultValue = "",
options,
select: selectProps,
selectProps,
}) => (
<Controller
name={name}
Expand Down
2 changes: 2 additions & 0 deletions src/components/index.tsx → src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import MuiRhfTextField from "./MuiRhfTextField";
import MuiRhfSelect from "./MuiRhfSelect";
import MuiRhfCheckbox from "./MuiRhfCheckbox";
import MuiRhfAutocompleteSingle from "./MuiRhfAutocompleteSingle";
import MuiRhfAutocompleteMultiple from "./MuiRhfAutocompleteMultiple";

export {
MuiRhfForm,
MuiRhfTextField,
MuiRhfSelect,
MuiRhfCheckbox,
MuiRhfAutocompleteSingle,
MuiRhfAutocompleteMultiple,
};
79 changes: 79 additions & 0 deletions src/components/tests/form.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React from "react";

import { render } from "@testing-library/react";
import { renderHook } from "@testing-library/react-hooks";

import { useForm } from "react-hook-form";

import { MuiRhfForm } from "../";

describe("Form render", () => {
it("render basic form", () => {
const { result } = renderHook(() => useForm());
const { control, errors /**, loading */ } = result.current;
render(
<MuiRhfForm
control={control}
errors={errors}
fields={[
[{ name: "firstName" }, { name: "lastName" }],
[{ name: "email" }],
[{ name: "rememberMe", type: "checkbox" }],
]}
/>
);
});

it("render complex form", () => {
const { result } = renderHook(() => useForm());
const { control, errors /**, loading */ } = result.current;
render(
<MuiRhfForm
control={control}
errors={errors}
headers={[{ title: "Company section" }]}
fields={[
[
{
type: "autocompleteSingle",
name: "company",
props: {
autocompleteProps: { options: ["Company A", "Company B"] },
},
},
{
type: "autocompleteMultiple",
name: "collaborator",
props: {
autocompleteProps: {
options: ["Collaborator A", "Collaborator B"],
},
},
},
],
]}
/>
);
});

it("render basic form with hideConditions", () => {
const { result } = renderHook(() => useForm());
const { control, errors /**, loading */ } = result.current;
render(
<MuiRhfForm
control={control}
errors={errors}
fields={[
[
{ name: "firstName" },
{
name: "lastName",
// Do not display lastName field when user is John Doe
hideCondition: { firstName: (value) => value === "John Doe" },
},
],
]}
/>
);
});
});
58 changes: 57 additions & 1 deletion src/components/tests/render.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import { renderHook } from "@testing-library/react-hooks";

import { useForm } from "react-hook-form";

import MuiRhfTextField from "../MuiRhfTextField";
import {
MuiRhfTextField,
MuiRhfSelect,
MuiRhfCheckbox,
MuiRhfAutocompleteSingle,
MuiRhfAutocompleteMultiple,
} from "../";

describe("Basic render", () => {
it("render MuiRhfTextField", () => {
Expand All @@ -15,4 +21,54 @@ describe("Basic render", () => {
<MuiRhfTextField control={control} errors={errors} name="textField" />
);
});
it("render MuiRhfAutocompleteSingle", () => {
const { result } = renderHook(() => useForm());
const { control, errors /**, loading */ } = result.current;
render(
<MuiRhfAutocompleteSingle
control={control}
errors={errors}
name="autocompleteSingleField"
autocompleteProps={{
options: [],
}}
/>
);
});

it("render MuiRhfAutocompleteMultiple", () => {
const { result } = renderHook(() => useForm());
const { control, errors /**, loading */ } = result.current;
render(
<MuiRhfAutocompleteMultiple
control={control}
errors={errors}
name="autocompleteMultipleField"
autocompleteProps={{
options: [],
}}
/>
);
});

it("render MuiRhfCheckbox", () => {
const { result } = renderHook(() => useForm());
const { control, errors /**, loading */ } = result.current;
render(
<MuiRhfCheckbox control={control} errors={errors} name="checkboxField" />
);
});

it("render MuiRhfSelect", () => {
const { result } = renderHook(() => useForm());
const { control, errors /**, loading */ } = result.current;
render(
<MuiRhfSelect
control={control}
errors={errors}
name="selectField"
options={[]}
/>
);
});
});
7 changes: 4 additions & 3 deletions src/models/fields/typing.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Control, FieldErrors } from "react-hook-form";
import { TextFieldProps, SelectProps, CheckboxProps } from "@material-ui/core";
import { AutocompleteProps } from "@material-ui/lab";

/** Common fields props */
export type MuiRhfFieldProps = {
Expand All @@ -18,7 +19,7 @@ export type MuiRhfTextFieldProps = MuiRhfFieldProps &
/** Select */
export type MuiRhfSelectProps = MuiRhfFieldProps & {
defaultValue?: unknown;
select?: SelectProps;
selectProps?: SelectProps;
options: {
value: string | number | readonly string[] | undefined;
label: string;
Expand All @@ -34,7 +35,7 @@ export type MuiRhfCheckboxProps = MuiRhfFieldProps &
/** Autocomplete */
export type MuiRhfAutocompleteProps = MuiRhfFieldProps & {
defaultValue?: unknown;
textField?: Omit<TextFieldProps, "onChange">;
textFieldProps?: Omit<TextFieldProps, "onChange">;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
autocomplete?: any;
autocompleteProps: any;
};
Loading

0 comments on commit eb672fc

Please sign in to comment.