React Testing-Library-测试在第一个useEffect挂钩中设置状态的Promise

时间:2020-05-04 14:46:17

标签: javascript reactjs unit-testing react-hooks react-testing-library

我有一个useEffect挂钩,它在安装组件时加载,如下所示:

useEffect(() => {
   listFiles().then(keys => {
      setKeys(keys)
      console.log(keys)
   }).catch(err => {
        showFail(err.message)
   })
}, [])

我正在尝试使用react testing-library来测试该功能,只需使用render函数即可:

beforeEach(() => {
  render(<Dashboard />)
})

但是,当我运行任何可以解决诺言并设置状态的测试时:

jest.mock('../utils/storage', () => ({
    listFiles: jest.fn(() => Promise.resolve([])),
}))

最后,我收到一条奇怪的警告消息,内容是使用act来包装事件:

  Warning: An update to Dashboard inside a test was not wrapped in act(...).

    When testing, code that causes React state updates should be wrapped into act(...):

    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */

    This ensures that you're testing the behavior the user would see in the browser. Learn more at .. 
        in Dashboard

      18 |     useEffect(() => {
      19 |         listFiles().then(keys => {
    > 20 |             setKeys(keys)
         |             ^
      21 |             console.log(keys)
      22 |         }).catch(err => {
      23 |             showFail(err.message)

我曾尝试将渲染器包装在act中,但似乎没有任何改变。

关于我在这里做错什么的任何建议吗?我应该以其他方式渲染吗?

提前谢谢!

2 个答案:

答案 0 :(得分:2)

当您尝试在组件完成更新所有状态之前进行断言时,通常会发生此错误。

请注意,在listFiles内部您正在呼叫setKeys(keys),并会更新状态。

您应await将新密钥(或文件)显示在文档中:

expect(await findByText('some file name or key')).toBeInTheDocument();
// more asserts here

或者,您可以Demo调用该模拟程序(尽管我认为上面的选项更好)。

await waitFor(() => expect(listFilesMock).toHaveBeenCalled());
// more asserts here

React Testing库应该已经将以上方法包装在act中,因此您不需要这样做


React waitFor中的act()是什么:

编写UI测试时,可以将诸如渲染,用户事件或数据获取之类的任务视为与用户界面交互的“单元”。 React提供了一个名为act()的帮助程序,可以确保在进行任何断言之前,已经处理了与这些“单元”相关的所有更新并将其应用于DOM。

名称行为来自“排列行为声明”模式。


有用的链接:

答案 1 :(得分:0)

就我而言,我没有嘲笑 useEffect 异步函数。

component.test.tsx:

df1 <- structure(list(Location = c("A", "B"), 
                      Job1 = c(1L, 4L), 
                      Job2 = c(2L, 5L), 
                      Job3 = c(3L, 6L), 
                      Total = 6:7), 
                      class = "data.frame", row.names = c(NA, -2L))

df2 <- structure(list(Location = c("A", "B"), 
                      Job2 = 0:1, 
                      Job1 = c(1L, 4L), 
                      Job3 = c(1L, 1L), 
                      Total = c(2L, 6L)), 
                      class = "data.frame", row.names = c(NA, -2L))

component.tsx:

test('Working useEffect hook', () => {
  const dbCallMock = jest.fn(() => Promise.resolve())
  render(<Tracks dbCallMock ={dbCallMock} />)
}