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

为何Jest测试预期与实际值不符却显示通过?附相关代码与报错

问题排查:Jest测试预期失败却通过 + UnhandledPromiseRejectionWarning警告

我来帮你拆解这两个问题的根源和修复方案:


一、Jest测试预期不匹配却显示通过的原因

你的测试代码里,try-catch的错误处理逻辑完全绕过了Jest的失败检测机制,导致断言失败时Jest根本不知道测试出问题了。先看你的核心代码:

it('User is already present as a supplier', (done) => { 
  const store = mockStore({}, [{ type: 'get_user', data: { } }]); 
  return store.dispatch(userGetAction({ role: 'supplier' }, () => {}))
    .then(() => { 
      try { 
        expect(store.getActions()[0].data.disabled).toEqual(true); 
        expect(store.getActions()[0].data.errormessage).toEqual('User is already present as a assitantbuyer'); 
      } catch (err) { 
        console.log(err); // 只打印错误,没告诉Jest测试失败
      } 
      done(); // 不管有没有错误,都标记测试完成
    })
    .catch(() => { 
      done(); // 同样,catch里直接结束测试,没传递错误
    }); 
});

具体问题:

  1. 断言错误被吞掉:当expect不匹配时会抛出错误,但你在try-catch里只打印了错误,没有把这个错误传给done(err)——Jest只有收到done(err)才会标记测试失败,否则只要done()被调用,就默认测试通过。
  2. 预期值拼写错误:从控制台输出能看到,实际错误信息是"User is already present as a assitant buyer"(多了空格),但你的预期值是"User is already present as a assitantbuyer",这也是断言不匹配的直接原因。

修复方案:

去掉多余的try-catch,让Jest自动捕获断言错误,同时正确使用done:

it('User is already present as a supplier', (done) => { 
  const store = mockStore({}, [{ type: 'get_user', data: { } }]); 
  store.dispatch(userGetAction({ role: 'supplier' }, () => {}))
    .then(() => { 
      expect(store.getActions()[0].data.disabled).toEqual(true); 
      // 修正拼写,和实际值匹配
      expect(store.getActions()[0].data.errormessage).toEqual('User is already present as a assitant buyer'); 
      done(); // 只有断言成功才结束测试
    })
    .catch(err => { 
      done(err); // 把错误传给Jest,标记测试失败
    }); 
});

更推荐用async/await简化代码(不需要手动管理done):

it('User is already present as a supplier', async () => { 
  const store = mockStore({}, [{ type: 'get_user', data: { } }]); 
  await store.dispatch(userGetAction({ role: 'supplier' }, () => {}));
  
  expect(store.getActions()[0].data.disabled).toEqual(true); 
  expect(store.getActions()[0].data.errormessage).toEqual('User is already present as a assitant buyer'); 
});

二、UnhandledPromiseRejectionWarning警告的原因

你的Redux Thunk代码里,Promise链的错误处理有漏洞,导致部分rejection没有被正确捕获。看你的代码:

const buyerAction = (data = {}, cb) => dispatch => axios({ 
  method: 'POST', 
  url: `http://localhost:3001/api/manageUsers`, 
  headers: { 'x-access-token': authService.getAccessToken() }, 
  data 
}).then(res => new Promise((resolve, reject) => { 
  if (res.status === 200 && res.data) { 
    dispatch({ type: 'buyer_created', data: res.data.message }); 
    if (data.role === 'buyer') { 
      axios({ 
        method: 'POST', 
        url: `http://localhost:3001/api/populateBuyerLookUp`, 
        headers: { 'x-access-token': authService.getAccessToken() }, 
        data 
      })
      .then((response) => { 
        resolve(response); 
      }).catch((err) => { 
        reject(err); 
      }); 
    } 
    cb(res.data.message); // 这里会在populate请求完成前执行cb
  } else { 
    reject(res); 
  } 
}))
.catch(() => { 
  console.log('error'); // 只打印错误,没处理rejection
});

具体问题:

  1. 外层catch吞掉了错误:当内层Promise(比如populateBuyerLookUp请求失败)被reject时,外层的catch只打印了error,但没有重新抛出错误。如果调用buyerAction的地方没有额外的.catch(),Node.js就会抛出UnhandledPromiseRejectionWarning。
  2. cb调用时机错误:当data.role === 'buyer'时,你在发起populateBuyerLookUp请求后立刻调用了cb,但这个请求是异步的,会导致cb在请求完成前执行,可能引发逻辑错误。
  3. 嵌套Promise增加了错误处理复杂度:嵌套的Promise链让错误传递路径不清晰,容易遗漏处理。

修复方案:

重构Promise链,改用链式then,并正确处理错误传递:

const buyerAction = (data = {}, cb) => dispatch => axios({ 
  method: 'POST', 
  url: `http://localhost:3001/api/manageUsers`, 
  headers: { 'x-access-token': authService.getAccessToken() }, 
  data 
}).then(res => {
  // 先判断请求是否成功,失败则抛出错误
  if (!(res.status === 200 && res.data)) {
    throw new Error('Request failed or no data received');
  }
  dispatch({ type: 'buyer_created', data: res.data.message }); 
  
  // 如果是buyer角色,执行populate请求,否则直接返回当前res
  if (data.role === 'buyer') {
    return axios({ 
      method: 'POST', 
      url: `http://localhost:3001/api/populateBuyerLookUp`, 
      headers: { 'x-access-token': authService.getAccessToken() }, 
      data 
    });
  }
  return res;
}).then(response => {
  // 确保cb在所有异步操作完成后执行
  cb(response.data?.message || response.data);
  return response;
}).catch(err => {
  console.error('Error in buyerAction:', err);
  // 重新抛出错误,让调用者可以捕获并处理
  throw err;
});

关键修复点:

  • 去掉嵌套的Promise,改用链式then,让错误可以沿着链自动传递。
  • 在catch里打印错误后重新抛出,这样调用buyerAction的地方可以通过.catch()处理错误,避免警告。
  • 把cb的调用放到最后一个then里,确保所有异步操作完成后再执行回调。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:05:23