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
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.
To learn more about Mocking in Jest, you should read the official documentation on:
You can also look at Enzyme's ShallowWrapper
API documentation
// TextInput.test.tsx
import React from 'react';
import { useField } from 'formik'; // package will be auto mocked
import TextInput from '...';
jest.mock('formik'); // formik package is auto mocked
describe("<TextInput/>", () => {
it("Match Snapshot", () => {
const mockMeta = {
touched: false,
error: "",
initialError: "",
initialTouched: false,
initialValue: "",
value: "",
}
const mockField = {
value: "",
checked: false,
onChange: jest.fn(),
onBlur: jest.fn(),
multiple: undefined,
name: "firstName",
};
useField.mockReturnValue([mockField, mockMeta]);
const mockProps = {...};
expect(
shallow(<TextInput {...mockProps} />).debug()
).toMatchSnapshot();
});
});
// TextInput.tsx
import React from 'react';
import { useField } from 'formik';
import ...
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}
/>
</>
);
}
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With