使用 react-testing-library 测试卸载
Test unmounting with react-testing-library
我对 when/how 查询的元素得到更新感到困惑。例如:
我有一个计数按钮。当它数到 3 时,它就消失了。
import React, { useState } from "react";
export default () => {
const [count, setCount] = useState(0);
return (
<div>
{count < 3 && (
<button onClick={() => setCount(count + 1)}>{count}</button>
)}
</div>
);
};
我正在这样测试它:
test("Counter counts up and disappears", () => {
const { queryByText } = render(<App" />);
const button = queryByText("0");
expect(button.textContent).toEqual("0");
fireEvent.click(button);
expect(button.textContent).toEqual("1");
fireEvent.click(button);
expect(button.textContent).toEqual("2");
fireEvent.click(button);
expect(button).toBe(null);
});
测试失败并出现以下错误:
expect(received).toBe(expected)
Expected value to be (using ===):
null
Received:
<button>2</button>
为什么按钮元素知道它的文本内容已经改变?我们不需要在每次点击后 运行 queryByText("1")
和 queryByText("2")
。
为什么它不知道按钮在上次单击后已被卸载?如果我们想检查它是否确实为空,我们确实需要做 queryByText("3")
。
这是代码沙箱:
https://codesandbox.io/s/react-testing-library-demo-76zhi
我猜测它是关于react-dom
和jsdom
(也被测试使用)如何工作的。
(如有不妥请指正或告知!我会删除。)
按钮类型 return by queryByText
是 HtmlElment
react
或 react-dom
只是最小化 dom 操作的任务,最终 jsdom
仍然会进行文本更改和按钮删除工作.
由于测试工具使用的是jsdom
,我检查了removeChild
部分代码,相信they are following W3C specification。我假设在 dom 操作级别,jsdom
会像浏览器一样工作。因此我模拟了你的代码:
const btn = document.getElementById('btn');
const btnContainer = document.getElementById('btnContainer');
btn.textContent = '1';
console.log('btn after click 1: ' + btn);
btn.textContent = '2';
console.log('btn after click 2: ' + btn);
btnContainer.removeChild(btn);
console.log('btn after removed: '+ btn);
<div id='btnContainer'><button id='btn'>0<button></div>
- 如你所见,从
div
中移除后,btn
变量仍然是[object HTMLButtonElement]
也许这类似于对包含已定义对象的数组使用 splice
,初始 obj 仍然保持不变?
const obj = { 'a': 1};
const arr = [obj];
arr[0]['a'] = 2;
arr.splice(0, -1);
console.log(obj)
因此,我认为更多的是。
另外,可能不复用查询结果,这种情况下总是重新查询,结果会更符合预期。
P.S。我发现有一个方法调用toBeInTheDocument
!
我对 when/how 查询的元素得到更新感到困惑。例如:
我有一个计数按钮。当它数到 3 时,它就消失了。
import React, { useState } from "react";
export default () => {
const [count, setCount] = useState(0);
return (
<div>
{count < 3 && (
<button onClick={() => setCount(count + 1)}>{count}</button>
)}
</div>
);
};
我正在这样测试它:
test("Counter counts up and disappears", () => {
const { queryByText } = render(<App" />);
const button = queryByText("0");
expect(button.textContent).toEqual("0");
fireEvent.click(button);
expect(button.textContent).toEqual("1");
fireEvent.click(button);
expect(button.textContent).toEqual("2");
fireEvent.click(button);
expect(button).toBe(null);
});
测试失败并出现以下错误:
expect(received).toBe(expected)
Expected value to be (using ===):
null
Received:
<button>2</button>
为什么按钮元素知道它的文本内容已经改变?我们不需要在每次点击后 运行 queryByText("1")
和 queryByText("2")
。
为什么它不知道按钮在上次单击后已被卸载?如果我们想检查它是否确实为空,我们确实需要做 queryByText("3")
。
这是代码沙箱: https://codesandbox.io/s/react-testing-library-demo-76zhi
我猜测它是关于react-dom
和jsdom
(也被测试使用)如何工作的。
(如有不妥请指正或告知!我会删除。)
按钮类型 return by
queryByText
是 HtmlElmentreact
或react-dom
只是最小化 dom 操作的任务,最终jsdom
仍然会进行文本更改和按钮删除工作.由于测试工具使用的是
jsdom
,我检查了removeChild
部分代码,相信they are following W3C specification。我假设在 dom 操作级别,jsdom
会像浏览器一样工作。因此我模拟了你的代码:
const btn = document.getElementById('btn');
const btnContainer = document.getElementById('btnContainer');
btn.textContent = '1';
console.log('btn after click 1: ' + btn);
btn.textContent = '2';
console.log('btn after click 2: ' + btn);
btnContainer.removeChild(btn);
console.log('btn after removed: '+ btn);
<div id='btnContainer'><button id='btn'>0<button></div>
- 如你所见,从
div
中移除后,btn
变量仍然是[object HTMLButtonElement]
也许这类似于对包含已定义对象的数组使用splice
,初始 obj 仍然保持不变?
const obj = { 'a': 1};
const arr = [obj];
arr[0]['a'] = 2;
arr.splice(0, -1);
console.log(obj)
因此,我认为更多的是
另外,可能不复用查询结果,这种情况下总是重新查询,结果会更符合预期。
P.S。我发现有一个方法调用toBeInTheDocument
!