This is my test file:
import List from '../List';
import { render, screen } from '@testing-library/react';
let data = ['one', 'two', 'three'];
describe('Component: List', () => {
let { container } = render(<List items={data} />);
test('(1) list length', () => {
let li = container.querySelectorAll('li');
expect(li.length).toBe(3);
});
test('(2) values in list', () => {
expect(screen.getByText('one')).toBeInTheDocument();
expect(screen.getByText('two')).toBeInTheDocument();
expect(screen.getByText('three')).toBeInTheDocument();
});
});
and I wrote this component:
const List = ({ items }) => {
return (
<ul>
{
items.map((item, index) => <li key={index}>{item}</li>)
}
</ul>
)
}
export default List;
My tests don't pass, I get this error for the (2) values in list
:
TestingLibraryElementError: Unable to find an element with the text: one. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
In the event that, test (2) passes when I comment or remove test (1) :
describe('Component: List', () => {
let { container } = render(<List items={data} />);
// test('(1) list length', () => {
// let li = container.querySelectorAll('li');
// expect(li.length).toBe(3);
// });
test('(2) values in list', () => {
expect(screen.getByText('one')).toBeInTheDocument();
expect(screen.getByText('two')).toBeInTheDocument();
expect(screen.getByText('three')).toBeInTheDocument();
});
});
Does container
effect on other selectors?
CodePudding user response:
Because RTL will unmount React trees that were mounted with render
after each test. This is called cleanup.
Please note that this is done automatically if the testing framework you're using supports the
afterEach
global and it is injected to your testing environment (like mocha, Jest, and Jasmine). If not, you will need to do manual cleanups after each test.
You only render the List
component once in describe
block. When the first test is finished, RTL will unmount the List
component, there is nothing in "screen", that's why your second test failed.
There are two ways to solve this:
To make this even easier, you can also simply import @testing-library/react/dont-cleanup-after-each which
will do the same thing. Just make sure you do this before importing @testing-library/react
. You could do this with Jest's setupFiles
configuration:
If you are using jestjs as your testing framework
{
// ... other jest config
setupFiles: ['@testing-library/react/dont-cleanup-after-each']
}
But multiple test cases use the same component, and the order in which the tests are executed is out of order, which can cause tests to interact with each other.
Simply put: Test cases are not isolated from each other and rely on the same test data.
2. Create fresh test data and test double for each test case, isolate tests.
import List from './';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import React from 'react';
let data = ['one', 'two', 'three'];
describe('Component: List', () => {
// let { container } = render(<List items={data} />);
test('(1) list length', () => {
let { container } = render(<List items={data} />);
let li = container.querySelectorAll('li');
expect(li.length).toBe(3);
});
test('(2) values in list', () => {
render(<List items={data} />);
expect(screen.getByText('one')).toBeInTheDocument();
expect(screen.getByText('two')).toBeInTheDocument();
expect(screen.getByText('three')).toBeInTheDocument();
});
});
Or, render
the component in beforeEach()
hook.