React 测试库:waitFor 与 act

han*_*ruh 11 javascript asynchronous typescript reactjs react-testing-library

我有一个通过回调更改状态的异步方法:

class Demo{
  callback: () => void;
    
  async triggerCallback() {
    this.callback();
  }

}
Run Code Online (Sandbox Code Playgroud)

此回调用于隐藏/显示元素:

const DemoComponent: React.FunctionComponent<Props> = ({Demo}) =>{
  const [show, setShow] = useState(false);

  const changeStateCallback = () => {
    setState(true);
  }

  useEffect(() =>{
   Demo.callback = changeStateCallback;
  }, []);

  
  return(
    <>
      {show && <p>Foo</p>}
    </>
  )
};
Run Code Online (Sandbox Code Playgroud)

我现在想测试这个,我仍在学习使用 Jest 和 React 测试库进行测试,所以一开始我有:

it("test", async () => {
  const Demo = new Demo();

  render(<DemoComponent Demo={Demo}/>);

  await Demo.triggerCallback();

  expect(screen.queryByText("Foo")).toBeTruthy();
}
Run Code Online (Sandbox Code Playgroud)

这失败了,因为它抱怨 Demo.triggerCallback(); 必须包含在 act() 中:

测试时,导致 React 状态更新的代码应包装到 act(...) 中:

act(() => { /* 触发更新状态的事件/ }); /断言输出 */

我对 async/await 规则做了如下操作:

it("test", async () => {
  const Demo = new Demo();

  render(<DemoComponent Demo={Demo}/>);

  await act( async () =>{
      await Demo.triggerCallback();
  };

  expect(screen.queryByText("Foo")).toBeTruthy();
}
Run Code Online (Sandbox Code Playgroud)

它再次失败,说我无法使行为异步:

警告:传递给 ReactTestUtils.act(...) 函数的回调不得返回任何内容。

看起来您编写了 ReactTestUtils.act(async () => ...),或者从传递给它的回调返回了一个 Promise。不支持将异步逻辑放入 ReactTestUtils.act(...) 中。

经过对文档和谷歌的一些研究,我发现了这个 waitFor() 方法,但与期望一起使用,例如:

await waitFor(() => {
    expect(getByText('1')).toBeInTheDocument();
  });
Run Code Online (Sandbox Code Playgroud)

但为此,我将 act() 替换为 waitFor(),因为它是我在 React 测试库中找到的少数异步方法之一。最终外观(我将其包装在 try/catch 中以防万一):

it("test", async () => {
  const Demo = new Demo();

  render(<DemoComponent Demo={Demo}/>);
  
  try {
    await waitFor( async () =>{
        await Demo.triggerCallback();
    };
  } catch(e) {
    fail("Test failed": + e);
  }

  expect(screen.queryByText("Foo")).toBeTruthy();
}
Run Code Online (Sandbox Code Playgroud)

并且测试通过了!现在……这是正确的吗?只是因为它有效,我不确定解决方案,所以希望得到一些反馈。我觉得我在做一些非法的事情,因为我只能找到 waitFor() 和 Expect() 的例子,而没有其他的。