在这种情况下,react-testing-library 找不到元素
react-testing-library doesn't find element in this case
这是我的测试文件:
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();
});
});
我写了这个组件:
const List = ({ items }) => {
return (
<ul>
{
items.map((item, index) => <li key={index}>{item}</li>)
}
</ul>
)
}
export default List;
我的测试没有通过,我收到 (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.
如果我评论或删除测试 (1) 时测试 (2) 通过:
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();
});
});
container
对其他选择器有影响吗?
因为 RTL 将在每次测试后卸载使用 render
挂载的 React 树。这叫做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.
您只在 describe
块中渲染一次 List
组件。当第一个测试完成后,RTL 将卸载 List
组件,“屏幕”中没有任何内容,这就是为什么你的第二个测试失败。
有两种方法可以解决这个问题:
为了使这更容易,您也可以简单地导入 @testing-library/react/dont-cleanup-after-each which
将做同样的事情。只需确保在导入 @testing-library/react
之前执行此操作。您可以使用 Jest 的 setupFiles
配置来做到这一点:
如果您使用 jestjs 作为测试框架
{
// ... other jest config
setupFiles: ['@testing-library/react/dont-cleanup-after-each']
}
但是多个测试用例使用同一个组件,测试的执行顺序乱了,会导致测试相互影响。
简单的说:测试用例不是相互隔离的,依赖同一个测试数据.
2。为每个测试用例创建新的测试数据和测试替身,隔离测试。
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();
});
});
或者,render
beforeEach()
挂钩中的组件。
更新:RTL 清理如何工作?
并回复您的评论:清理是否取决于每个 test() 或 it() 块?
每次使用render
函数将组件挂载到容器中,mountedContainers集会添加组件容器。
mountedContainers 设置在模块范围内定义。
每次测试后,cleanup 函数将从容器中卸载组件,从文档中删除容器,并从 mountedContainers
集合中删除容器。
所以你在describe
函数体中渲染组件,describe函数在整个测试过程中只执行一次。 mountedContainers
添加您的组件一次,当执行第一个测试用例时,mountedContainers
set 将删除它。然后“屏幕”什么也没有,第二次测试失败
这是我的测试文件:
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();
});
});
我写了这个组件:
const List = ({ items }) => {
return (
<ul>
{
items.map((item, index) => <li key={index}>{item}</li>)
}
</ul>
)
}
export default List;
我的测试没有通过,我收到 (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.
如果我评论或删除测试 (1) 时测试 (2) 通过:
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();
});
});
container
对其他选择器有影响吗?
因为 RTL 将在每次测试后卸载使用 render
挂载的 React 树。这叫做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.
您只在 describe
块中渲染一次 List
组件。当第一个测试完成后,RTL 将卸载 List
组件,“屏幕”中没有任何内容,这就是为什么你的第二个测试失败。
有两种方法可以解决这个问题:
为了使这更容易,您也可以简单地导入 @testing-library/react/dont-cleanup-after-each which
将做同样的事情。只需确保在导入 @testing-library/react
之前执行此操作。您可以使用 Jest 的 setupFiles
配置来做到这一点:
如果您使用 jestjs 作为测试框架
{
// ... other jest config
setupFiles: ['@testing-library/react/dont-cleanup-after-each']
}
但是多个测试用例使用同一个组件,测试的执行顺序乱了,会导致测试相互影响。
简单的说:测试用例不是相互隔离的,依赖同一个测试数据.
2。为每个测试用例创建新的测试数据和测试替身,隔离测试。
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();
});
});
或者,render
beforeEach()
挂钩中的组件。
更新:RTL 清理如何工作?
并回复您的评论:清理是否取决于每个 test() 或 it() 块?
每次使用render
函数将组件挂载到容器中,mountedContainers集会添加组件容器。
mountedContainers 设置在模块范围内定义。
每次测试后,cleanup 函数将从容器中卸载组件,从文档中删除容器,并从 mountedContainers
集合中删除容器。
所以你在describe
函数体中渲染组件,describe函数在整个测试过程中只执行一次。 mountedContainers
添加您的组件一次,当执行第一个测试用例时,mountedContainers
set 将删除它。然后“屏幕”什么也没有,第二次测试失败