-
Notifications
You must be signed in to change notification settings - Fork 54
React Testing Library unittest
We Have to migrate from enzyme to RTL because React 18 has a internal breaking change that makes enzyme dead by design. React now schedule render. So we have to rewrite a bunch of tests suite (360).
But RTL came with a real difference: no access to react component, no access to state. It looks like a more end to end approach. As we still need unittest we have to find tricks to tests only one component and not the entire subset.
Also RTL is based on jsdom so there is limitations, we will try to list them.
Snapshot are nice to keep a trace of the render. Just do it once per component seems enough. This is usefull to see impact when a DOM is changed for example after upgrading a library.
Avoid doing 10 snapshots has they do not fit any tests except it('should render', () => {
Component is about limitation of the responsabilities, so it is ok to mock underlying components or dependencies. This is not considered as a code smell ref as mentionned in this article, in the context of composition.
The goal of mock can be:
- make it easier to test the current component
- get the internal state of the component you test
First tips is to use dataset.props
:
jest.mock('../../pickers/CalendarPicker', () => {
return props => <div data-testid="CalendarPicker" data-props={JSON.stringify(props)} />;
});
// ..tests
// then
const props = JSON.parse(screen.getByTestId('CalendarPicker').dataset.props);
expect(props).toMatchObject({
manageFocus: true,
other: 'custom props',
selectedDate: '2007-01-01T23:00:00.000Z',
useUTC: false,
});
The drawback is you don't have access to function but this is often OK as function are most of the time event handler. You can add buttons to manage event handler out of the scope of your current component. But this is usefull only if the current component create this handler. if it is only a pass through it doesn't make sens to unittest it.
jest.mock('../../views/DateTimeView', () =>
jest.fn(props => (
<div data-testid="DateTimeView" data-props={JSON.stringify(props)}>
<button onClick={() => props.onTitleClick()}>Select MonthYearView</button>
</div>
)),
);
We should avoid mock far away dependency, for example if A
depends on B
depends on C
and you tests A
avoid to mock C
and prefer to mock B
.
As we use jsdom it means it is not a real browser, so no graphical representation, only part of the DOM.
- scroll or wheel event are not supported
- getBoundingClientRect does not exists
If you fall into this case you have the following choices
- try to add the missing function on DOM
- use a real browser (slower tests)
window.HTMLElement.prototype.getBoundingClientRect = () => ({ width: 42 });
wrapper.setProps => rerender
- const wrapper = mount(
+ const { rerender} = render(
//...
- wrapper.setProps({
+ rerender( // same react but now with this new props