3

我对查询元素何时/如何更新感到困惑。例如:

我有一个计数的按钮。当它数到 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

4

1 回答 1

2

这是关于如何react-domjsdom(也被测试使用)的工作原理。

(如果猜测不可接受,请纠正我或让我知道!我会删除这个。)

  1. 返回的按钮类型queryByTextHtmlElment

  2. react或者react-dom只是最小化 dom 操作的任务,最终jsdom仍然会进行文本更改和按钮删除工作。

  3. 由于测试工具正在使用jsdom,我检查了removeChild部分代码,并相信它们遵循 W3C 规范。我假设在 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>

  1. 如您所见,从 中删除后divbtn变量仍然是[object HTMLButtonElement] Maybe 它类似于使用splice包含已定义对象的数组,初始 obj 仍然保持不变?

const obj = { 'a': 1};
const arr = [obj];
arr[0]['a'] = 2;
arr.splice(0, -1);
console.log(obj)


因此,我认为更多的是关于垃圾收集在 javascript中的工作方式。

另外,可能不重用查询结果,在这种情况下总是再次查询,结果会更符合预期。


PS我发现有一个方法调用toBeInTheDocument

于 2019-07-25T18:02:40.973 回答