javascript - 当状态更新不影响 UI 时防止 "not wrapped in act(...)"Jest 警告

标签 javascript reactjs jestjs react-testing-library testing-library

我试图找出是否有一种方法可以防止 Jest/testing-library 抛出“未包装在 act(...)”警告,当我在状态更新后没有任何内容可以断言时,会导致发生警告,或者我是否应该忽略此警告。

假设我有这个简单的组件:

import React, {useEffect, useState} from 'react';
import {getData} from 'services';

const MyComponent = () => {
  const [arr, setArr] = useState([]);

  useEffect(() => {
    (async () => {
      const {items} = await getData();
      setArr(items);
    })();
  }, []);

  return (
    <div>
      {!(arr.length > 0) && <p>no array items</p>}
      {arr.length > 0 && (
        <ul>
          {arr.map(item => (
            <li key={item.id}>{item.name}</li>
          ))}
        </ul>
      )}
    </div>
  );
};

export default MyComponent;

假设我想简单地测试该组件是否渲染正常,即使 getData() 没有为我返回任何数据。

所以我有一个这样的测试:

import React from 'react';
import {getData} from 'services';
import {render, screen} from 'testUtils';
import MyComponent from './MyComponent';

jest.mock('services', () => ({
  getData: jest.fn(),
}));

it('renders', () => {
  getData.mockResolvedValue({items: []});

  render(<MyComponent />);

  expect(screen.getByText('no array items')).toBeInTheDocument();
});

此测试将通过,但我会收到“未包装在 act(...)”警告,因为测试将在 getData() 有机会完成之前完成。

在这种情况下,来自 getData() 的响应将 arr 设置为与我最初将其设置为相同的值(空数组)成分。因此,异步函数完成后,我的 UI 不会发生变化——我仍然只是看一段“没有数组项”——所以我实际上没有任何可以断言的等待状态更新的内容来完成。

我可以expect(getData).toHaveBeenCalledTimes(1),但这不会等待函数调用后状态实际更新。

我尝试在测试中任意暂停,以便为 setArr(items) 的发生留出时间:

it('renders', async () => {
  getData.mockResolvedValue({items: []});

  render(<MyComponent />);

  expect(screen.getByText('no array items')).toBeInTheDocument();
  
  await new Promise(resolve => setTimeout(resolve, 2000));

  expect(screen.getByText('no array items')).toBeInTheDocument();
});

但这似乎没有帮助,老实说我不确定为什么。

有没有办法通过仅修改测试来处理这种情况?

我确信我可以通过重构 MyComponent 来解决问题,例如,将 arr 作为 prop 传递给 MyComponent 并将 getData() 调用移动到父组件,或者创建一些仅用于测试的自定义 Prop ,这些 Prop 将完全跳过 getData() 调用,但我不想纯粹为了避免测试中的警告而修改组件。

我正在使用testing-library/react ,v11.2.2。

最佳答案

您可以使用 findByText(getByTextwaitFor 的组合)来确保断言解析时所有更新均已发生。

it('renders', async () => {
    getData.mockResolvedValue({items: []});
    render(<MyComponent />);
    expect(await screen.findByText('no array items')).toBeInTheDocument();
});

关于javascript - 当状态更新不影响 UI 时防止 "not wrapped in act(...)"Jest 警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66283312/

相关文章:

javascript - 使用带有 2 个按钮的 jQuery 旋转图像

javascript - 作为 native 应用程序运行的 iPhone 网络应用程序

android - 为什么我的 this.setState 在函数中不起作用?

jestjs - 开 Jest 不在多项目模式下选择配置

javascript - 在 React Native 中使用构造函数创建对象

javascript - 如何从 Node.JS 套接字流触发浏览器下载?

javascript - 为什么 componentWillReceiveProps(nextProps) 不记录/触发

javascript - 在后退按钮单击 (REACTJS) 上执行代码

unit-testing - 如何测试vue Js metaInfo

javascript - 开 Jest ,用不同的参数模拟同一个函数两次