TL;DR
How to write unit test with Jest & Enzyme for components with 'useField' hook? On shallow render I get this error
Warning: Formik context is undefined, please verify you are calling
useFormikContext() as child of a <Formik> component
TypeError: Cannot read property 'getFieldProps' of undefined
Details
The project build with
- React
- TypeScript
- Formik
- Material UI
- Jest Enzyme
It's a learning project, so I am playing around with different approaches. That's why I've put all components in different files thought it might not be necessary.
Structure:
Formik.tsx
|
| AddContactForm.tsx
|
| TextInput.tsx
| TextInput.test.tsx
Details:
Formik.tsx Just a wrapper where we have all properties of the form
<Formik
initialValues={initialValues}
validationSchema={...}
onSubmit={...};
component={AddContactForm}
/>
AddContactForm.tsx Here I am passing field meta and props to input. It seems to be not the best solution, I'd like to use useField() hook inside a component itself
<Form>
<TextInput
label="First Name"
name={"firstName"}
placeholder="Jane"
field={getFieldProps("firstName")}
meta={getFieldMeta("firstName")}
/>
<button type="submit">Submit</button>
</Form>
TextInput.tsx This is current solution - I can write unit tests for it - for example snapshot testing.
const TextInput: React.FC<MyInput> = React.memo(
({ label, field, meta}: MyInput) => {
return (
<>
<TextField
label={label}
type="text"
{...field}
error={meta?.touched && meta?.error ? true : undefined}
helperText={meta?.touched ? meta?.error : undefined}
/>
</>
);
}
);
TextInput.test.tsx Here I have to write big mockProps object to mock all things :(
describe("<TextInput/>", () => {
it("Match Snapshot", () => {
const mockProps: MyInput = {
label: "label",
name: "name",
placeholder: "placeholder",
meta: {
touched: false,
error: "",
initialError: "",
initialTouched: false,
initialValue: "",
value: "",
},
field: {
value: "",
checked: false,
onChange: jest.fn(),
onBlur: jest.fn(),
multiple: undefined,
name: "firstName",
},
};
expect(
shallow(
<TextInput
label="label"
name="name"
placeholder="placeholder"
{...mockProps.meta}
{...mockProps.field}
/>
)
).toMatchSnapshot();
});
});
Instead, what I want is to get field and meta not by props, but with useField() hook.
TextField.tsx
const TextInput: React.FC<MyInput> = React.memo(
({ label, ...props }: MyInput) => {
const [field, meta] = useField(props);
return (
<>
<TextField
label={label}
type="text"
{...field}
{...props}
error={meta?.touched && meta?.error ? true : undefined}
helperText={meta?.touched ? meta?.error : undefined}
/>
</>
);
}
);
But then I have not clue how to write a test for it. It seems like it wants to have Formik context inside a test, but it's not possible to use useFormikContext() hook in test file as it violates rules of hooks usage.