React 测试库清理在 Jest 描述块中不起作用
React Testing Library cleanup not working in Jest's describe bocks
我有一些正在进行的测试,这是按预期工作的:
describe("Parent", () => {
afterEach(() => {
cleanup();
jest.resetModules();
});
describe("Test 1", () => {
const wrapper = render(
<MockProvider>
<MyComponent />
</MockProvider>
);
test("1 ", () => {
expect(wrapper.baseElement).toMatchSnapshot();
expect(wrapper.getByText("Apply").disabled).toBe(true);
});
});
describe("Test 2", () => {
test("1 ", () => {
const wrapper = render(
<MockProvider>
<MyComponent />
</MockProvider>
);
console.log(wrapper.getByText("Apply").disabled);
expect(1).toBe(1);
});
});
});
然而,当我将第二个渲染函数移出测试时出现错误:
describe("Parent", () => {
afterEach(() => {
cleanup();
jest.resetModules();
});
describe("Test 1", () => {
const wrapper = render(
<MockProvider>
<MyComponent />
</MockProvider>
);
test("1 ", () => {
expect(wrapper.baseElement).toMatchSnapshot();
expect(wrapper.getByText("Apply").disabled).toBe(true);
});
});
describe("Test 2", () => {
const wrapper = render(
<MockProvider>
<MyComponent />
</MockProvider>
);
test("1 ", () => {
console.log(wrapper.getByText("Apply").disabled);
expect(1).toBe(1);
});
});
});
我得到的错误是
Found multiple elements with the text: Apply
我在控制台中看到该组件被渲染了两次,所以我认为关于 describe 块的清理功能一定没有正常工作。这很奇怪,因为我们已经进行了酶测试,并且设置和拆卸工作正常。
我 运行 正在解决一个单独的问题,但在中间找到了 你的 问题的可能答案。
Jest describe
在任何测试 运行 之前按顺序阻塞 运行。 Source
因此,除了变量作用域之外,您基本上不应该在描述块中执行代码。如果您需要设置一个变量或呈现一个跨多个测试使用的模拟,请将其放在生命周期方法中,例如 beforeAll
或 beforeEach
.
要理解这一点,我们需要稍微了解一下 Jest
运行 我们的测试以及 React Testing Library
如何渲染我们的组件。
开玩笑
考虑下面的代码并尝试猜测输出是什么:
describe('First describe', () => {
console.log('First describe');
it('First test', () => {
console.log('First test');
});
});
describe('Second describe', () => {
console.log('Second describe');
it('Second test', () => {
console.log('Second test');
});
});
输出(悬停查看):
先描述一下
第二个描述
第一次测试
第二次测试
请注意,所有 describe
方法都在测试开始之前初始化为 运行。
这应该已经让您对问题有所了解,但现在让我们看看 RTL。
React 测试库
考虑下面的代码并尝试猜测 DOM 在控制台中的样子:
const Greeting = () => 'Hello world';
describe('First describe', () => {
const wrapper = render(<Greeting />);
it('First test', () => {
console.log(wrapper.debug());
});
});
describe('Second describe', () => {
render(<Greeting />);
});
输出(悬停查看):
<code><body>
<div>Hello world</div>
<div>Hello world</div>
</body>
当我们不为 render
函数指定基本元素时,它总是使用相同的 document.body
当我们未指定自定义容器时,<div>
元素包装 Hello world
由 RTL 添加。
默认情况下所有 RTL 查询都绑定到基本元素--document.body
在这种情况下。
因此,
getByText('Hello world'); // will find two elements and throw
这就是 code in RTL 对于 render
函数的样子。 (半伪代码)
if(!baseElement) {
baseElement = document.body // body will be shared across renders
}
if(!container) {
baseElement.appendChild(document.createElement('div')) // wraps our component
}
ReactDOM.render(component, container)
return { container, baseElement, ...getQueriesForElement(baseElement) }
解决这个问题
执行以下操作之一:
- 在
it
或 test
方法中调用 render
- 在查询中指定
container
- 为每个
render
指定不同的基本元素
另一个快速修复方法是在将组件传递给 render()
之前用“React.Fragment”包装您的组件
test ('should find text in <Component />', () => {
const {getByText} = render (<><Component /></>)
const divElement = getByText (/Find Text/i)
expect (divElement).toBeInTheDocument ()
})
我有一些正在进行的测试,这是按预期工作的:
describe("Parent", () => {
afterEach(() => {
cleanup();
jest.resetModules();
});
describe("Test 1", () => {
const wrapper = render(
<MockProvider>
<MyComponent />
</MockProvider>
);
test("1 ", () => {
expect(wrapper.baseElement).toMatchSnapshot();
expect(wrapper.getByText("Apply").disabled).toBe(true);
});
});
describe("Test 2", () => {
test("1 ", () => {
const wrapper = render(
<MockProvider>
<MyComponent />
</MockProvider>
);
console.log(wrapper.getByText("Apply").disabled);
expect(1).toBe(1);
});
});
});
然而,当我将第二个渲染函数移出测试时出现错误:
describe("Parent", () => {
afterEach(() => {
cleanup();
jest.resetModules();
});
describe("Test 1", () => {
const wrapper = render(
<MockProvider>
<MyComponent />
</MockProvider>
);
test("1 ", () => {
expect(wrapper.baseElement).toMatchSnapshot();
expect(wrapper.getByText("Apply").disabled).toBe(true);
});
});
describe("Test 2", () => {
const wrapper = render(
<MockProvider>
<MyComponent />
</MockProvider>
);
test("1 ", () => {
console.log(wrapper.getByText("Apply").disabled);
expect(1).toBe(1);
});
});
});
我得到的错误是
Found multiple elements with the text: Apply
我在控制台中看到该组件被渲染了两次,所以我认为关于 describe 块的清理功能一定没有正常工作。这很奇怪,因为我们已经进行了酶测试,并且设置和拆卸工作正常。
我 运行 正在解决一个单独的问题,但在中间找到了 你的 问题的可能答案。
Jest describe
在任何测试 运行 之前按顺序阻塞 运行。 Source
因此,除了变量作用域之外,您基本上不应该在描述块中执行代码。如果您需要设置一个变量或呈现一个跨多个测试使用的模拟,请将其放在生命周期方法中,例如 beforeAll
或 beforeEach
.
要理解这一点,我们需要稍微了解一下 Jest
运行 我们的测试以及 React Testing Library
如何渲染我们的组件。
开玩笑
考虑下面的代码并尝试猜测输出是什么:
describe('First describe', () => {
console.log('First describe');
it('First test', () => {
console.log('First test');
});
});
describe('Second describe', () => {
console.log('Second describe');
it('Second test', () => {
console.log('Second test');
});
});
输出(悬停查看):
先描述一下
第二个描述
第一次测试
第二次测试
请注意,所有 describe
方法都在测试开始之前初始化为 运行。
这应该已经让您对问题有所了解,但现在让我们看看 RTL。
React 测试库
考虑下面的代码并尝试猜测 DOM 在控制台中的样子:
const Greeting = () => 'Hello world';
describe('First describe', () => {
const wrapper = render(<Greeting />);
it('First test', () => {
console.log(wrapper.debug());
});
});
describe('Second describe', () => {
render(<Greeting />);
});
输出(悬停查看):
<code><body>
<div>Hello world</div>
<div>Hello world</div>
</body>
当我们不为 render
函数指定基本元素时,它总是使用相同的 document.body
当我们未指定自定义容器时,<div>
元素包装 Hello world
由 RTL 添加。
默认情况下所有 RTL 查询都绑定到基本元素--document.body
在这种情况下。
因此,
getByText('Hello world'); // will find two elements and throw
这就是 code in RTL 对于 render
函数的样子。 (半伪代码)
if(!baseElement) {
baseElement = document.body // body will be shared across renders
}
if(!container) {
baseElement.appendChild(document.createElement('div')) // wraps our component
}
ReactDOM.render(component, container)
return { container, baseElement, ...getQueriesForElement(baseElement) }
解决这个问题
执行以下操作之一:
- 在
it
或test
方法中调用render
- 在查询中指定
container
- 为每个
render
指定不同的基本元素
另一个快速修复方法是在将组件传递给 render()
test ('should find text in <Component />', () => {
const {getByText} = render (<><Component /></>)
const divElement = getByText (/Find Text/i)
expect (divElement).toBeInTheDocument ()
})