警告:测试中应用程序的更新未包含在酶和钩子中的 act(...) 中

Dan*_*ial 7 act reactjs jestjs enzyme react-hooks

我已经编写了这个组件。它使用钩子和状态获取数据。获取后,加载状态将更改为 false 并显示侧边栏。

我在使用 Jest 和 Enzyme 时遇到了问题,因为它确实在我的单元测试中为 Act 发出了警告。一旦我将行为添加到我的笑话和酶中,测试就失败了!

// @flow
import React, { useEffect, useState } from 'react';
import Sidebar from '../components/Sidebar';
import fetchData from '../apiWrappers/fetchData';

const App = () => {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const getData = async () => {
      try {
        const newData = await fetchData();
        setData(newData);
        setLoading(false);
      }
      catch (e) {
        setLoading(false);
      }
    };
    getData();
    // eslint-disable-next-line
  }, []);
  return (
    <>
      {!loading
        ? <Sidebar />
        : <span>Loading List</span>}
    </>
  );
};
export default App;
Run Code Online (Sandbox Code Playgroud)

而且,我添加了这样一个完美的测试。

import React from 'react';
import { mount } from 'enzyme';
import fetchData from '../apiWrappers/fetchData';
import data from '../data/data.json';
import App from './App';

jest.mock('../apiWrappers/fetchData');

const getData = Promise.resolve(data);
fetchData.mockReturnValue(getData);

describe('<App/> Rendering using enzyme', () => {
  beforeEach(() => {
    fetchData.mockClear();
  });

  test('After loading', async () => {
    const wrapper = mount(<App />);
    expect(wrapper.find('span').at(0).text()).toEqual('Loading List');

    const d = await fetchData();
    expect(d).toHaveLength(data.length);

    wrapper.update();
    expect(wrapper.find('span').exists()).toEqual(false);
    expect(wrapper.html()).toMatchSnapshot();
  });
});
Run Code Online (Sandbox Code Playgroud)

所以,我收到了警告:

Warning: An update to App 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 */
});
Run Code Online (Sandbox Code Playgroud)

我确实使用 { act } react-dom/test-utils 解决了这样的警告。

Warning: An update to App 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 */
});
Run Code Online (Sandbox Code Playgroud)

但是,然后我的测试失败了。

<App/> Rendering using enzyme › After loading

expect(received).toEqual(expected) // deep equality

Expected: false
Received: true

  35 | 
  36 |       wrapper.update();
> 37 |       expect(wrapper.find('span').exists()).toEqual(false);
Run Code Online (Sandbox Code Playgroud)

有人知道为什么会失败吗?谢谢!

"react": "16.13.1",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.3",
Run Code Online (Sandbox Code Playgroud)

tmh*_*005 10

这个问题一点也不新鲜。您可以在此处阅读完整的讨论:https : //github.com/enzymejs/enzyme/issues/2073

总而言之,目前为了修复act警告,您必须等待一段时间才能更新您的包装器,如下所示:

const waitForComponentToPaint = async (wrapper) => {
  await act(async () => {
    await new Promise(resolve => setTimeout(resolve));
    wrapper.update();
  });
};

test('After loading', async () => {
  const wrapper = mount(<App />);
  expect(wrapper.find('span').at(0).text()).toEqual('Loading List');
  
  // before the state updated
  await waitForComponentToPaint(wrapper);
  // after the state updated

  expect(wrapper.find('span').exists()).toEqual(false);
  expect(wrapper.html()).toMatchSnapshot();
});
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的评论,我实际上已经阅读了该链接。而且,我刚刚尝试过你的代码。但是,即使在使用代码后我也会收到相同的警告。绕过它的唯一方法是将我的整个测试包装在这样的行为中。`test.only('加载后', async () =&gt; { wait act(async () =&gt; { /* 实际测试 */ });});` 但这太多了!我在我的“&lt;App /&gt;”中使用“useEffect”,这可能是一个问题。我看过这个评论https://github.com/enzymejs/enzyme/issues/2073,但对我来说实现它很复杂。您还有其他建议可以在不包装我的每一个测试的情况下完成吗? (2认同)