尝试在 jest 中同时使用 jest-fetch-mocks 模拟多个 API 时,如何避免 act(() =>{} 中的包装测试警告?

问题描述 投票:0回答:1

我正在尝试为一个 React 应用程序编写单元测试,该应用程序调用多个静态 API 端点来填充一堆不同的下拉元素选项。

下面是我的反应组件的精简版本。我做了一个定制的钩子

useFetchReferenceData
负责调用所有参考 API 并设置下拉选项。

export function SearchSubmitterProfile() {
  const [search, setSearch] = useState(true);
  const [viewResults, setViewResults] = useState(false);
  const [createSubmitterProfileState, setCreateSubmitterProfileState] = useState(INITIAL_STATE);

  useFetchReferenceData(
    createSubmitterProfileState,
    setCreateSubmitterProfileState
  );

  return (
    <div id="search-sub-profile" key="search-sub-profile" className={styles.grayBg}>
      {search ? (
        <ConnectedSearchView
        />
      ) : null}
      {viewResults ? (
        <ConnectedSubmitterProfile
        />
      ) : null}
    </div>
  );
}

export default SearchSubmitterProfile;

在 useFetchReferenceData 中,我有大约 14 个以下 fetch 调用和下拉构建器函数,如下所示。这些函数中的每一个都在自定义挂钩文件底部的异步 useEffect 中调用

  const { run: getLanguageIndicators } = useFetchye(`${subApiUrl}/submlanguageind`, {
    credentials: 'include',
    headers: getDefaultHeaders(),
    defer: true,
  });

  const buildLanguagIndDropdown = async () => {
    const currentState = { ...createSubmitterProfileState };
    const { data } = await getLanguageIndicators();
    if (data.status === 200) {
      const result = [];
      result.push(DROPDOWN_STARTER);
      data.body.map((element) => result.push({
        value: `${element.dialect_language_code}`,
        label: `${element.dialect_language_code} - ${element.dialect_name}`,
      }));
      currentState.staticFieldState.submitterLanguageIndicator.options = result;
      setCreateSubmitterProfileState(currentState);
    } else {
      errorList.push('Error retrieving language indicators');
    }
  };

  useEffect(() => {
    const fetchAllData = async () => {
      await buildRegionsDropDown();
      await buildLanguagIndDropdown();
      ... 14 more of these
    };
    fetchAllData().catch(console.error);
  }, []);

在我的测试中,我尝试模拟所有这些 fetch 调用以覆盖 useFetchReferenceData 文件中的所有行。测试如下所示,我使用 jest-fetch-mock 库来模拟一系列 API 调用。

describe('Search Submitter Profile reference data', () => {
  beforeEach(() => {
    enableFetchMocks();
    fetch.mockResponses(
      [
        JSON.stringify(mockRegions),
        { status: 200 },
      ],
      [
        JSON.stringify(mockLanguageIndicators),
        { status: 200 },
      ],
      ... 14 more
    );
  });

  it('validate the search information view', async () => {
    render(
      <UserContext.Provider value={{ loggedInUser }}>
        <SearchSubmitterProfile />
      </UserContext.Provider>
    );
  });
});

上述测试通过,但我收到一堆以下警告,我想知道如何修复。

  console.error
    Warning: An update to SearchSubmitterProfile 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 */
    });
    /* assert on the output */
reactjs jestjs mocking jest-fetch-mock
1个回答
0
投票

您的测试似乎没有测试任何内容 - 它调用

render
但之后什么也不做。您是否在代码片段中省略了
expect
调用?

无论如何,警告告诉您

fetch
调用正在异步完成,这会触发重新渲染,并且测试代码在不知情的情况下不会批准 React 重新渲染。如果您通过模拟用户输入同步触发重新渲染,那么您可以将这些用户输入事件包装在
act
中(请参阅 此示例)。由于它们是异步发生的,所以这是行不通的。您有几种选择:

  • 按照 React 文档的数据获取示例,您可以尝试将
    render
    调用包装在
    act
    中。我没有尝试过这种方法。
  • 如果您正在使用 测试库(看起来像这样),那么您可以使用
    waitFor
    findBy
    查询
    之一来确保在测试继续之前所有后台操作已完成。这是我的正常做法。
  it('validate the search information view', async () => {
    render(
      <UserContext.Provider value={{ loggedInUser }}>
        <SearchSubmitterProfile />
      </UserContext.Provider>
    );

    await screen.findByText('something that only displays once all fetches finish');
    // Or
    await waitFor(() => expect(someComplexCriteria).toBeTruthy());

    // Continue with test assertions
  });
© www.soinside.com 2019 - 2024. All rights reserved.