Here is an example test suite using Jest and Enzyme but you could just as easily use another testing framework like react-testing-library.
Please note: this example is heavily reliant on Formik version 1.5.8
. As of version 2.x.x
, Formik no longer uses class components under the hood and has switched to functional components.
// Versions used: react: 16.13.1 jest: 24.9.0 enzyme: 3.11.0 formik: 1.5.8
// Helper function (entirely optional) - when mounting // components that use the store, theming etc we need // to wrap our components in their relevant providers export const TestApp = ({ children, ...rest }: { children: React.ReactNode }) => { const store = configureStore(); return ( <Provider store={store}> <IntlProvider> <ThemeProvider theme={theme}> <BrowserRouter> {React.Children.map(children, (child) => React.isValidElement(child) ? React.cloneElement(child, rest) : child )} </BrowserRouter> </ThemeProvider> </IntlProvider> </Provider> ); }; // Helper function - uses act() under the hood from react-dom/test-utils const actImmediate = (wrapper: ReactWrapper) => act( () => new Promise<void>((resolve) => { setImmediate(() => { wrapper.update(); resolve(); }); }) ); // Helper function - sets Formik fields directly using it's instance const setFormikFields = (wrapper: ReactWrapper, values: Record<string, string>) => { return new Promise((resolve) => wrapper .find('Formik') .instance() .setState({ values }, () => { wrapper.update(); resolve(); }) ); }; const updateLoginMock = jest.fn(); // data-qa tags for easy element selection within the component const qa = { form: '[data-qa="form"]', passwordField: '[data-qa="passwordField"]', emailField: '[data-qa="emailField"]', }; describe('Given a MyComponent component', () => { let wrapper: ReactWrapper; describe('When it is rendered', () => { beforeEach(() => { wrapper = mount( <TestApp> <MyComponent updateLogin={updateLoginMock} /> </TestApp> ); }); describe('When the form fields receive a value', () => { const fields = { password: 'Pass123$', email: 'some@email.com', }; beforeEach(async () => { await setFormikFields(wrapper, fields); // sets the form fields directly using Formik's instance. This happens asynchronously so we need to use async/await }); it('Then the form fields should have the correct value', () => { expect(wrapper.find(qa.passwordField).prop('value')).toBe(fields.password); expect(wrapper.find(qa.emailField).prop('value')).toBe(fields.email); }); describe('When the form is submitted (form is valid)', () => { beforeEach(async () => { wrapper.find(qa.form).simulate('submit'); await actImmediate(wrapper); // uses act() under the hood from react-dom/test-utils }); it('Then updateEmailMock should be called with the correct data', () => { expect(updateEmailMock).toHaveBeenCalledWith({ password: fields.password, email: fields.email }); }); }); }); }); });
Top comments (0)