【问题标题】:Why does react hook throw the act error when used with fetch api?为什么 react hook 与 fetch api 一起使用时会抛出 act 错误?
【发布时间】:2019-07-11 22:26:52
【问题描述】:

每当我发出 API 请求并更新状态时,我的测试套件中都会不断收到 Warning: An update to App inside a test was not wrapped in act(...).

我正在使用 react-testing-library。我也尝试使用 ReactDOM 测试工具,得到了相同的结果。我尝试的另一件事是将容器包装在 act 中,仍然得到相同的结果。

请注意:我的应用程序有效并且我的测试通过了。我只需要知道我做错了什么,或者是否是 react-dom 包中的错误导致该错误出现。模拟控制台错误并将其静音是不好的。

global.fetch = require('jest-fetch-mock');

it('should clear select content item', async () => {
    fetch.mockResponseOnce(JSON.stringify({ results: data }));

    const { container } = render(<App />);

    const content = container.querySelector('.content');

    await wait();

    expect(content.querySelectorAll('.content--item').length).toBe(2);
});

这里是钩子的实现:

const [data, setData] = useState([]);
const [error, setError] = useState('');

const fetchInitData = async () => {
    try {
        const res = await fetch(API_URL);
        const data = await res.json();

        if (data.fault) {
            setError('Rate limit Exceeded');
        } else {
            setData(data.results);
        }
    } catch(e) {
        setError(e.message);
    }
};

useEffect(() => {
    fetchInitData();
}, [isEqual(data)]);

【问题讨论】:

  • 这一切都在一个函数中吗?
  • 是的。让我补充说它正在工作并且我的测试通过了。唯一的问题是烦人的错误

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


【解决方案1】:

这是一个已知问题,请在 Github https://github.com/kentcdodds/react-testing-library/issues/281查看此问题

【讨论】:

    【解决方案2】:

    要摆脱act() 警告,您需要确保您的承诺同步解决。你可以阅读here如何做到这一点。

    总结:

    解决方案有点复杂:

    • 我们用一个可以解决问题的实现来全局填充 Promise “立即”承诺,例如承诺
    • 使用自定义 babel 设置转换您的 javascript,如本仓库中的设置
    • 使用 jest.runAllTimers();现在这也将刷新承诺任务队列

    【讨论】:

      【解决方案3】:

      我遇到了这个问题,放弃了使用等待和异步,而是使用了 jest faketimers 等等,所以你的代码应该是这样的。

      global.fetch = require('jest-fetch-mock');
      
      it('should clear select content item', /*async */ () => {
          jest.useFakeTimers();
          fetch.mockResponseOnce(JSON.stringify({ results: data }));
      
          const { container } = render(<App />);
      
          const content = container.querySelector('.content');
      
          // await wait();
          act(() => {
            jest.runAllTimers();
          });
      
          expect(content.querySelectorAll('.content--item').length).toBe(2);
      });

      【讨论】:

        【解决方案4】:

        对于像我一样在一年多后偶然发现此问题的任何人,Giorgio 提到的问题已得到解决,wait 已被替换为 waitFor,如下所述:

        https://testing-library.com/docs/dom-testing-library/api-async/

        既然如此,我认为现在警告的解决方案应该是这样的:

        import { render, waitFor } from '@testing-library/react';
        // ...
        
        it('should clear select content item', async () => {
            fetch.mockResponseOnce(JSON.stringify({ results: data }));
        
            const { container } = render(<App />);
        
            const content = container.querySelector('.content');
        
            await waitFor(() =>
                expect(content.querySelectorAll('.content--item').length).toBe(2);
            );
        });
        

        在我的例子中,我有一个 App 组件在 useEffect 钩子中异步加载数据,因此我在每次测试中都收到此警告,使用 beforeEach 呈现 App。这是我的案例的具体解决方案:

          beforeEach(async () => {
            await waitFor(() => render(<App />));
          });
        

        【讨论】:

          猜你喜欢
          • 2021-03-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-28
          相关资源
          最近更新 更多