React 测试库:waitFor vs act

React Testing Library: waitFor vs act

提问人:hanuruh 提问时间:7/13/2021 更新时间:6/26/2023 访问量:7090

问:

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

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

}

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

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

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

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

  
  return(
    <>
      {show && <p>Foo</p>}
    </>
  )
};

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

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

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

  await Demo.triggerCallback();

  expect(screen.queryByText("Foo")).toBeTruthy();
}

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

测试时,导致 React 状态更新的代码应包装到 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();
}

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

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

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

在文档和谷歌中进行了一些研究后,我发现了这个 waitFor() 方法,但与 expect 一起,例如:

await waitFor(() => {
    expect(getByText('1')).toBeInTheDocument();
  });

但为了它,我将 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();
}

测试通过了!现在。。。这是正确的吗?仅仅因为它有效,我不确定解决方案,所以希望对此提供一些反馈。我觉得我在做一些非法的事情,因为我只能找到带有 expect() 的 waitFor() 示例,而没有别的。

javascript reactjs typescript 异步 react-testing-library

评论

2赞 Shota 7/13/2021
我认为你违反了 React 的单向数据绑定实践。你试图从普通的 Javascript 类操作 React 的组件状态的原因是什么?
0赞 hanuruh 7/13/2021
我有一个用于 vanilla JS 服务器/客户端通信的 API,当我从服务器收到错误时,我想显示一个弹出窗口。
1赞 ourmaninamsterdam 7/14/2021
翔太说得有道理。当你的原版通信 API 出错时,它可能会将一个道具传递给 ,也许?或者你可以构建一个钩子来桥接你的普通 JS API,这样你就可以在 React 中使用它。DemoComponent
0赞 najuste 3/9/2023
感觉就像您正在尝试将两件事合二为一,即类演示行为和组件演示组件行为。一旦组件准备好,测试 DemoComponent 将测试 sreen 中的文本外观。“act”用于准备,如果你在文档中查看 recipies,你会看到 act 中渲染组件的示例。如果调用一个类是一个触发器,那么它将是这样的: act(() => {render(<DemoComponent demo={new Demo()} />, container);});然后你用 await waitFor((() => {expect(getByText('Foo')).toBeInTheDocument()}) 等待 Foo

答: 暂无答案