I'd like to write unit tests and make them really small. But I have a problem. React testing library unmounts root component every time test passes. So, I can do this
describe('Some test', () => {
const { rerender } = render(<Component prop1={0} />);
test('Title 1', () => {
// logic1
});
test('Title 2', () => {
rerender(<Component prop1={0} />);
// logic2
});
test('Title 3', () => {
rerender(<Component prop1={1} />);
// logic3
});
test('Title 4', () => {
rerender(null);
// logic4
});
});
I'd like to call rerender
function in each test and then add a specific logic for each test. But I'm getting an error Error: Cannot update an unmounted root.
from the 2nd test onwards.
I can write my test in this way
test('Some test', () => {
const { rerender } = render(<Component prop1={0} />);
// logic1
rerender(<Component prop1={0} />);
// logic2
rerender(<Component prop1={1} />);
// logic3
rerender(null);
// logic4
});
But in this case the test becomes too massive.
So, the question is: Is it possible to write tests in the first example? If yes, how is it possible?
you could import
@testing-library/react/pure
in all your tests that you don't want thecleanup
to run and theafterEach
won't be setup automatically.
If we import from @testing-library/react
, it will import from index.js file.
src/index.js
:
import {cleanup} from './pure'
// if we're running in a test runner that supports afterEach
// or teardown then we'll automatically run cleanup afterEach test
// this ensures that tests run in isolation from each other
// if you don't like this then either import the `pure` module
// or set the RTL_SKIP_AUTO_CLEANUP env variable to 'true'.
if (typeof process === 'undefined' || !process.env?.RTL_SKIP_AUTO_CLEANUP) {
// ignore teardown() in code coverage because Jest does not support it
/* istanbul ignore else */
if (typeof afterEach === 'function') {
afterEach(() => {
cleanup()
})
} else if (typeof teardown === 'function') {
// Block is guarded by `typeof` check.
// eslint does not support `typeof` guards.
// eslint-disable-next-line no-undef
teardown(() => {
cleanup()
})
}
}
export * from './pure';
As you can see in the source code, RTL calls the cleanup
function imported from the ./pure
module inside the afterEach
hook.
We could import functions such as render
from the @testing-library/react/pure
module and call the cleanup
function manually when needed.
import { render } from '@testing-library/react/pure';
import React from 'react';
const Component = ({ prop1 }) => <div>{prop1}</div>;
describe('Some test', () => {
const { rerender, asFragment } = render(<Component prop1={0} />);
test('Title 1', () => {
rerender(<Component prop1={0} />);
// logic1
expect(asFragment().firstChild).toMatchInlineSnapshot(`
<div>
0
</div>
`);
});
test('Title 2', () => {
rerender(<Component prop1={1} />);
// logic2
expect(asFragment().firstChild).toMatchInlineSnapshot(`
<div>
1
</div>
`);
});
});