You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用React-testing-library测试依赖自定义Hook的React组件?

问题原因

这个act(...)警告的本质是:你触发表单提交后,自定义Hook内的fetchData是异步函数,内部的状态更新(setLoading、请求结束后的setResponse/setError/setLoading(false))都属于微任务,会在测试用例的同步代码(也就是你写的expect断言)执行完成后才运行。React检测到组件在测试预期流程外发生了状态更新,因此抛出警告。

额外提一个你代码中的显性bug:自定义useMakeAsyncCall返回的加载状态字段是loading,但业务组件中解构写的是isLoading,会导致加载状态始终为undefined,需要先修正:

const { error, loading, fetchData } = useMakeAsyncCall({
  asyncFunctionToRun: () => signUpUser(),
  runOnMount: false,
});

修复方案

第一步:Mock异步请求

先Mock掉Firebase的signUpUser请求,避免真实请求发送,同时方便控制请求的返回状态:

// 示例,替换为你实际的signUpUser导入路径
jest.mock('./path/to/auth.js', () => ({
  signUpUser: jest.fn().mockResolvedValue({
    json: () => Promise.resolve({ success: true })
  })
}));

第二步:等待异步更新完成后再执行断言

React Testing Library提供的异步工具已经内置了act处理,不需要手动包裹act,两种常用方案按需选择:

方案1:用waitFor包裹断言(通用场景)

waitFor会等待内部异步逻辑执行完成后再运行断言,自动处理act包裹:

import { render, fireEvent, waitFor } from '@testing-library/react';

it('does things', async () => {
  const { container, getByTestId } = render(<Component/>);
  const form = getByTestId('form');
  
  fireEvent.submit(form);

  await waitFor(() => {
    expect(container.firstChild).toMatchSnapshot();
  });
});

方案2:用findBy*查询(需要匹配元素场景)

findBy*系列查询自带等待功能,本身也会把状态更新包裹在act内,适合测试加载态、成功/失败提示这类场景:

it('shows loading state after form submit', async () => {
  const { getByTestId, findByText } = render(<Component/>);
  const form = getByTestId('form');
  
  fireEvent.submit(form);

  // 自动等待加载文案出现
  const loadingTip = await findByText('提交中...');
  expect(loadingTip).toBeInTheDocument();
});

可选:单独测试自定义Hook

如果你需要单独测试useMakeAsyncCall的逻辑,可以使用@testing-library/react-hooks的renderHook工具配合waitFor测试,同样不会出现act警告。

内容的提问来源于stack exchange,提问作者Person

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 01:48:03