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)