微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

当状态更新不影响 UI 时,防止“不包含在行为...中”开玩笑警告

如何解决当状态更新不影响 UI 时,防止“不包含在行为...中”开玩笑警告

我试图弄清楚是否有办法防止 Jest/testing-library 在状态更新后没有任何可断言时抛出“notwrap in 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();
});

此测试将通过,但我会收到“notwrapped in 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 作为道具传递给 MyComponent 并将 getData() 调用移动到父组件,或者创建一些仅使用的自定义道具用于完全跳过 getData() 调用的测试,但我不想纯粹为了避免测试中的警告而修改组件。

我使用的是 testing-library/react,v11.2.2。

解决方法

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。