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

NodeJS Promise拒绝时JSON缺失key的单元测试问题排查

解决chai-as-promised断言被拒绝Promise时无法获取自定义错误对象的问题

我一眼就看出问题所在了——chai-as-promised的assert.isRejected默认期望被拒绝的是一个Error实例,而不是普通的JavaScript对象。

你现在的代码里,reject的是一个包含code和message的普通对象,但chai-as-promised在处理这种情况时,会自动把非Error类型的拒绝值转换成字符串(通常是取message字段,或者直接调用toString()),所以你只能看到message,code字段自然就丢失了,这就是断言失败的核心原因。

下面给你两种可行的解决思路:


方案1:让函数reject一个带自定义属性的Error实例(推荐)

这是更符合JavaScript错误处理规范的做法,毕竟Promise的reject通常用来传递错误信息,用Error实例能保留完整的调用栈等信息。

修改你的函数代码:

exports.validate = (strId) => {
  return new Promise((resolve, reject) => {
    if (!strId) {
      const validationError = new Error('Required header is not present in request');
      // 把自定义code挂载到Error实例上
      validationError.code = constants.ID_NOT_VALID;
      return reject(validationError);
      // 其余逻辑
    }
  });
}

然后调整测试代码,用rejectedWith结合属性断言,这样既能验证是Error类型,又能检查自定义的code和message:

it('should not be empty', async () => {
  await expect(validate.validateCorrelationId())
    .to.be.rejectedWith(Error)
    .and.have.property('code', constants.ID_NOT_VALID)
    .and.have.property('message', 'Required header is not present in request');
});

如果坚持用assert.isRejected,可以链式调用then来检查错误属性:

it('should not be empty', async () => {
  return assert.isRejected(validate.validateCorrelationId(), Error)
    .then(err => {
      assert.equal(err.code, constants.ID_NOT_VALID);
      assert.equal(err.message, 'Required header is not present in request');
    });
});

方案2:不修改原函数,直接断言被拒绝的普通对象

如果你不想改动现有函数的返回逻辑,可以直接捕获被拒绝的值,然后用深度相等断言来匹配整个对象:

it('should not be empty', async () => {
  // 直接捕获reject的值
  const rejectedErr = await validate.validateCorrelationId().catch(err => err);
  // 用deepEqual匹配整个对象
  assert.deepEqual(rejectedErr, {
    code: constants.ID_NOT_VALID,
    message: 'Required header is not present in request'
  });
});

或者用chai-as-promised的rejected结合deep.equal:

it('should not be empty', async () => {
  await expect(validate.validateCorrelationId())
    .to.be.rejected
    .and.deep.equal({
      code: constants.ID_NOT_VALID,
      message: 'Required header is not present in request'
    });
});

为什么你原来的测试会失败?

你之前用assert.isRejected(promise, errJson),chai-as-promised会把第二个参数当成Error的匹配条件(比如匹配message或者name),而不是直接匹配整个拒绝值。当拒绝值是普通对象时,它会尝试把对象转换成字符串来匹配,所以只会提取message字段,导致断言时找不到code,最终失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:26:19