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

React项目中如何用Jest测试Promise的then回调函数调用

测试React中Promise回调函数调用的问题解决

这个问题我太熟了!本质是Jest默认同步执行测试逻辑,在signupAPI返回的Promise完成并触发then回调前,测试就已经跑完了断言,所以handleSuccess还没被调用,导致测试失败。先回顾下你的代码:

待测试代码

const handleSubmit = (handleSuccess, handleErrors) => { 
  signupAPI(user) 
    .then(handleSuccess) 
    .catch(handleErrors); 
};

原测试代码(存在异步未等待问题)

test('should call handleSuccess', () => { 
  signupAPI.mockImplementation((user) => Promise.resolve(user)); 
  const handleSuccess = jest.fn(); 
  const handleErrors = jest.fn(); 
  handleSubmit(handleSuccess, handleErrors); 
  expect(signupAPI).toHaveBeenCalled(); // 测试通过 
  expect(handleSuccess).toHaveBeenCalled(); // 测试失败 
});

下面给你三种可行的解决方式:


方法1:用async/await等待异步操作

这是最直观的方式,要么修改handleSubmit让它返回Promise,要么等待微任务队列清空:

方案A:修改原函数返回Promise

先调整handleSubmit,让它返回API调用的Promise链:

const handleSubmit = (handleSuccess, handleErrors) => { 
  return signupAPI(user) 
    .then(handleSuccess) 
    .catch(handleErrors); 
};

然后测试时用await等待handleSubmit完成:

test('should call handleSuccess', async () => { 
  signupAPI.mockImplementation((user) => Promise.resolve(user)); 
  const handleSuccess = jest.fn(); 
  const handleErrors = jest.fn(); 
  
  await handleSubmit(handleSuccess, handleErrors); 
  
  expect(signupAPI).toHaveBeenCalled(); 
  expect(handleSuccess).toHaveBeenCalled(); 
});

方案B:不修改原函数,等待微任务

如果不想改动原函数,也可以用await Promise.resolve()来等待所有微任务(包括Promise的then回调)执行完毕:

test('should call handleSuccess', async () => { 
  signupAPI.mockImplementation((user) => Promise.resolve(user)); 
  const handleSuccess = jest.fn(); 
  const handleErrors = jest.fn(); 
  
  handleSubmit(handleSuccess, handleErrors); 
  await Promise.resolve(); // 等待微任务队列清空
  
  expect(signupAPI).toHaveBeenCalled(); 
  expect(handleSuccess).toHaveBeenCalled(); 
});

方法2:使用Jest的done回调

Jest支持传入done参数,当你确认异步操作完成后调用它,告诉Jest测试可以结束了:

test('should call handleSuccess', (done) => { 
  signupAPI.mockImplementation((user) => Promise.resolve(user)); 
  // 在handleSuccess的mock函数里执行断言并触发done
  const handleSuccess = jest.fn(() => {
    expect(signupAPI).toHaveBeenCalled(); 
    expect(handleSuccess).toHaveBeenCalled(); 
    done(); // 告知Jest测试完成
  }); 
  const handleErrors = jest.fn(); 
  
  handleSubmit(handleSuccess, handleErrors); 
});

这种方式不需要修改原函数,直接在回调触发时完成断言。


方法3:让测试函数返回Promise

Jest会自动等待测试函数返回的Promise完成,所以可以返回一个Promise来延迟断言:

test('should call handleSuccess', () => { 
  signupAPI.mockImplementation((user) => Promise.resolve(user)); 
  const handleSuccess = jest.fn(); 
  const handleErrors = jest.fn(); 
  
  handleSubmit(handleSuccess, handleErrors); 
  
  // 返回Promise,等待微任务执行后再断言
  return Promise.resolve().then(() => {
    expect(signupAPI).toHaveBeenCalled(); 
    expect(handleSuccess).toHaveBeenCalled(); 
  }); 
});

最后还要提醒一句:你的handleSubmit里用到了user变量,如果这是组件内的状态,测试时要确保它被正确初始化或者mock,不然可能会影响signupAPI的调用逻辑哦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:08:24