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

如何测试API调用成功/失败后返回布尔值的React异步自定义Hook

问题根源

你遇到的两个问题本质上都是同一个原因导致的:

  • waitForNextUpdate 是异步方法,返回Promise,你的测试用例没有用await等待它执行完成:
    1. 测试执行到expect(current.isValidPolicyReference).toBeFalsy()时,getPolicyByReference的异步 reject 逻辑还没走完,setIsValid(false)还没触发,自然拿不到false的返回值
    2. 测试用例同步执行完毕后,测试框架会直接卸载测试的Hook实例,等到异步 reject 触发setIsValid(false)时,组件已经卸载,就会抛出状态更新警告

另外你写的成功用例能通过属于侥幸:因为初始状态就是true,不需要等异步逻辑执行完成,两次断言本来就都是true,和异步逻辑走没走完没关系。

解决方案

不需要改mock getPolicyByReference的逻辑,也不需要直接mock axios,只需要给测试用例加上async/await即可:

// 失败用例修正后
test('should be falsy if the policy reference is invalid', async () => {
  (getPolicyByReference as jest.Mock).mockImplementationOnce(() =>
    Promise.reject(new Error('policy reference error'))
  );
  const {
    result,
    waitForNextUpdate,
  } = render();

  expect(result.current.isValidPolicyReference).toBeTruthy();

  // 等待异步逻辑执行完成、状态更新
  await waitForNextUpdate();

  expect(result.current.isValidPolicyReference).toBeFalsy();
});

同时建议把成功用例也改成async/await的写法,避免后续逻辑调整后出现不稳定的测试结果:

test('should be truthy if the policy reference is valid', async () => {
  (getPolicyByReference as jest.Mock).mockImplementationOnce(() =>
    Promise.resolve(true)
  );
  const {
    result,
    waitForNextUpdate,
  } = render();

  expect(result.current.isValidPolicyReference).toBeTruthy();

  await waitForNextUpdate();

  expect(getPolicyByReference).toHaveBeenCalledWith({
    token,
    tenant,
    policyReference,
  });
  expect(result.current.isValidPolicyReference).toBeTruthy();
});

额外优化建议

为了避免生产环境也出现「不能给未挂载组件更新状态」的警告,建议给Hook加上取消更新的逻辑:

React.useEffect(() => {
  let isMounted = true;
  async function fetchOnMount(): Promise<void> {
    try {
      await getPolicyByReference({
        policyReference: policyReference as string,
        tenant,
        token,
      });
    } catch (error) {
      // 只有组件还挂载的时候才更新状态
      if (isMounted) setIsValid(false);
    }
  }
  if (tenant !== '' && policyReference !== null && token !== '') {
    fetchOnMount();
  }
  // 组件卸载时标记为未挂载
  return () => {
    isMounted = false;
  };
}, [policyReference, tenant, token]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 10:15:04