reactjs - 测试时,导致 React 状态更新的代码应包装到 act(...)

标签 reactjs jestjs react-testing-library

我正在测试我的组件

ForecastButtons.js

export const ForecastButtons = ({ city }) => {
  const [payload, setPayload] = useState(null)

  const getData = () => {
    fetchCityData(city).then((payload) => setPayload(payload));
  }
  const location = payload?.location?.name;
  const currentTemp = payload?.current?.temp_c;

  return(
    <div className="sm:col-span-2">
      <p className="block text-sm font-medium text-gray-700">Select forecast</p>
        <button onClick={getData} className="mt-1 bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded" type='button'>
          Today
        </button>
        <p key={city?.location?.id} className='my-5'>
          { location ? `Current weather in ${location} is ${currentTemp} degrees ` : 'Please search for city to see current weather'}
        </p>
    </div>
  )
}

这是我测试的一部分:

    test('render weather into component',  async () => {
    
      const { getByText } = render(<ForecastButtons weather={weatherResponce} city={'London'} />);
      const button = getByText('Today')
    
      await act(async () => {
        await fireEvent.click(button)
      })
      expect(getByText('London')).toBeInTheDocument();
    })

请注意,这不是整个测试,只是不起作用的部分。错误如上。正如你所看到的,我向其中添加了 act() ,但它仍然不断抛出错误:当测试时,导致 React 状态更新的代码应该包装到 act(...)

最佳答案

我可以在 React Testing Library and the “not wrapped in act” Errors 中找到一些提示Medium 上,很多案例都解释得很好。

第一个有用的学习:

React testing library already integrated act with its APIs. So in most cases, we do not need to wrap render and fireEvent in act. For example:

// With react-testing-library
it("should render and update a counter", () => {
  // Render a component
  const { getByText } = render(<Counter />;
  ...  

  // Fire event to trigger component update
  fireEvent.click(getByText("Save"));
  ...
});

在我的例子中,我得到了错误(我作为初学者的假设),因为 fireEvent.click 触发 fetchData 被调用,这是一个异步调用。当它的响应返回时,fetchCityData/getData 将被调用,但此时,更新将发生在 React 的调用堆栈之外。

解决方案

在断言之前,使用 waitFor 等待组件更新完全完成。 waitFor 是 React 测试库提供的一个 API,用于等待包装的断言在某个超时窗口内通过。

我更改了部分测试代码,如下所示:

  test('renders responce into paragraph', async () => {
    render(<ForecastButtons weatherResponce={weatherResponce} city='London' />);
    const button = screen.getByRole('button');
    const label = screen.getByText('Please search for city to see current weather');
    fireEvent.click(button)
    await waitFor(() => {
      expect(label.textContent).toBe(`Current weather in ${weatherResponce.location.name} is ${weatherResponce.current.temp_c} degrees`);
    });
  })

weatherResponce 只是对模拟 HTTP 请求的模拟响应,我是用 nock 来做的。

关于reactjs - 测试时,导致 React 状态更新的代码应包装到 act(...),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69391350/

相关文章:

reactjs - 使用react-testing-library进行测试时可以手动触发状态更改吗?

reactjs - 我怎样才能忽略 react 警告? (不是 native 应用程序)

javascript - 为什么react中useState变量是 `const`?

vue.js - 如何在 stub 中触发事件? [vue-test-utils]

javascript - 如何在javascript中查找文档中存在的元素

javascript - 在 Jest 中调试单个测试

reactjs - 如何在 react 中使用 API 调用测试组件?

javascript - 在 React 中使用 jest.fn() 模拟获取

javascript - 未处理的 promise 拒绝 TypeError

javascript - 如何将文件从React应用程序上传到存储帐户下的Azure文件共享?