I'm new to React and confused about all the testing libraries. I got my test code to work but it seems redundant to have to call create()
from react-test-renderer in order to use its toMatchSnapshot()
and have to call render()
from @testing-library/react in order to use its assertions such as getByLabelText()
.
import {render} from '@testing-library/react';
import {act, create} from 'react-test-renderer';
it('renders a login screen', () => {
let mockInitialState: AppState = {
auth: initialAuthState
};
let component = <Root initialState={mockInitialState}/>;
let tree = null;
act(() => {
tree = create(component);
});
expect(tree).toMatchSnapshot();
const {getByLabelText, getByText} = render(component);
expect(getByLabelText(/Email Address.*/));
expect(getByLabelText(/Password*/));
expect(getByText('Sign in'));
});
As a newbie, it's hard for me to understand the difference between all these React libraries. But I'm thinking there must be a simpler way.
How can I simplify my test code so I only have to call one thing that renders the component so that I can do snapshot testing and more specific assertions?
render() comes from react testing library and renders your tree but also allows you to have all the get*() assertions. It allows you to test against the DOM.
React renders HTML to the web page by using a function called render(). The purpose of the function is to display the specified HTML code inside the specified HTML element. In the render() method, we can read props and state and return our JSX code to the root component of our app.
Jest. Jest was the most popular JavaScript unit testing framework in 2020. For web apps that are based on React, Jest is the preferred framework. Apart from React, Jest supports unit testing of Angular, VueJS, NodeJS, and others.
Jest provides a great iteration speed combined with powerful features like mocking modules and timers so you can have more control over how the code executes. React Testing Library is a set of helpers that let you test React components without relying on their implementation details.
I got the answer from Ziad Saab at Codementor.io:
create()
allows you test against the virtual DOM (i.e. the "React DOM")
render()
comes from react testing library and renders your tree but also allows you to have all the get*() assertions. It allows you to test against the DOM.
Here's how the code can be simplified:
it('renders a login screen', () => {
let mockInitialState: AppState = {
auth: initialAuthState
};
const {container, getByLabelText, getByText} = render(<Root initialState={mockInitialState}/>);
expect(container.firstChild).toMatchSnapshot();
expect(getByLabelText(/Email Address.*/));
expect(getByLabelText(/Password*/));
expect(getByText('Sign in'));
});
Ziad let me know that there was no reason to have act()
, it was something to work around a bug in create()
. Now that the code doesn't used create()
there is no need for act()
.
As a result, my snapshot now contains class
instead of className
because class
is what's in the actual HTML DOM whereas className
is its equivalent in React's "Virtual DOM".
(Before) Snapshot with create()
based on React's Virtual DOM:
className="MuiBox-root MuiBox-root-256"
(After) Snapshot with render()
based on HTML DOM:
class="MuiBox-root MuiBox-root-256"
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