I am writing a form component using react-final-form library. As component starts growing, I split it into multiple sub components such that parent component has the <Form>{... }</Form>
component and related <Field>{... }</Field>
are in separate components. Now, I'm trying to write unit test for my separated sub components containing <Field></Field>
, I'm getting the error as <Field>{... }</Field>
have dependency on <Form>{... }</Form>
and cannot run separately. Below is the exact error message which shows up when I try to run unit test.
useField must be used inside of a component
One way I can solve this is to mock my actual <Field>{... }</Field>
component in its unit test, but I feel that won't be a correct approach as for unit test I'm mocking the actual component which needs to get tested.
Could someone please help me what way should I go for ? Is it the right way to mock the component in its own unit test and then test it or should I have to think of restructuring my parent <Form>
and its sub components ? And how can I restructure it better, any ideas?
CodePudding user response:
Field
component uses useField hook, useField
hook uses useForm underly. useForm
uses React.useContext(ReactFinalFormContext) underly. As you can see, it uses ReactFinalFormContext
, so the component which uses this react context must be a descendant of ReactFinalFormContext.Provider. ReactFinalFormContext.Provider
is provided by Form
component.
I recommend you to use React Testing Library to test your react components.
It's not recommended to mock the component, you should test your components
in the way a user would use them. Users don't care what happens behind the scenes, they just see and interact with the output.
For more, see Why should I use React Testing Library
You should wrap your Field
custom component with a Form
component. See official test recipes
E.g.
it("should render via children render function", () => {
const { getByTestId } = render(
<Form onSubmit={onSubmitMock}>
{() => (
<form>
<Field name="name">
{({ input }) => <input {...input} data-testid="name" />}
</Field>
</form>
)}
</Form>,
);
expect(getByTestId("name")).toBeDefined();
})