繁体   English   中英

React testing-library - 测试在第一个 useEffect 挂钩中设置状态的 promise

[英]React testing-library - Testing a promise that set states in the first useEffect hook

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

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

我正在尝试使用反应测试库测试 function,只需使用渲染 function:

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

但是,当我运行任何解决 promise 并设置 state 的测试时:

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中,但它似乎并没有改变任何东西。

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

提前致谢!

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

请注意,在listFiles中,您正在调用setKeys(keys)并更新 state。

您应该await新密钥(或文件)出现在文档中:

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

或者,您可以等待模拟已被调用(尽管我认为上面的选项更好)。

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

上面的方法act已经被 React 测试库为你包装好了,所以你不需要这样做


React文档中的act()是什么:

在编写 UI 测试时,渲染、用户事件或数据获取等任务可以被视为与用户界面交互的“单元”。 React 提供了一个名为 act() 的帮助器,它确保在您做出任何断言之前,与这些“单元”相关的所有更新都已被处理并应用于 DOM。

名称 act 来自 Arrange-Act-Assert 模式。


有用的链接:

在我的情况下,我不是 mocking useEffect async function。

组件.test.tsx:

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

组件.tsx:

export const myComponent = (props: {
  dbCallMock: Function
}) => {
  const [state, setState] = useState<string[]>([])

  const getDbState= () => 
    db.state.toArray().then(gotState => setState(gotState))

  useEffect(
    () => (props.dbCallMock ? props.dbCallMock() : getDbState()),
    []
  )
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM