获取未处理的承诺拒绝警告使用摩卡/柴进行测试时

2022-08-30 02:10:43

因此,我正在测试一个依赖于事件发射器的组件。为此,我提出了一个使用Mocha + Chai的承诺的解决方案:

it('should transition with the correct event', (done) => {
  const cFSM = new CharacterFSM({}, emitter, transitions);
  let timeout = null;
  let resolved = false;
  new Promise((resolve, reject) => {
    emitter.once('action', resolve);
    emitter.emit('done', {});
    timeout = setTimeout(() => {
      if (!resolved) {
        reject('Timedout!');
      }
      clearTimeout(timeout);
    }, 100);
  }).then((state) => {
    resolved = true;
    assert(state.action === 'DONE', 'should change state');
    done();
  }).catch((error) => {
    assert.isNotOk(error,'Promise error');
    done();
  });
});

在控制台上,我收到“未处理的PromiseRejectionWarning”,即使拒绝函数被调用,因为它会立即显示消息“AssertionError:Promise error”

(节点:25754)未处理的PromiseRejectionWarning:未处理的 promise拒绝(拒绝id:2):AssertionError:Promise error:expected { Object (message, showDiff, ...) } to be falsy

  1. 应使用正确的事件进行转换

然后,在2秒后,我得到

错误:超时超过 2000 毫秒。确保在此测试中调用 done() 回调。

自从执行 catch 回调以来,这甚至更奇怪(我认为由于某种原因,断言失败阻止了其余的执行)

现在有趣的是,如果我注释掉测试,测试运行良好,在控制台中没有任何警告。它仍然“失败”,因为它执行捕获。
但是,我仍然无法理解这些错误。有人能启发我吗?assert.isNotOk(error...)


答案 1

此问题是由以下原因引起的:

.catch((error) => {
  assert.isNotOk(error,'Promise error');
  done();
});

如果断言失败,则会引发错误。此错误将导致永远不会被调用,因为代码在它之前出错了。这就是导致超时的原因。done()

“未处理的应许拒绝”也是由失败的断言引起的,因为如果在处理程序中抛出错误,并且没有后续的 catch() 处理程序,则错误将被吞噬(如本文中所述)。该警告提醒您注意这一事实。catch()UnhandledPromiseRejectionWarning

通常,如果您想在Mocha中测试基于承诺的代码,则应依靠Mocha本身已经可以处理承诺的事实。您不应使用 ,而应从测试中返回承诺。然后,摩卡将自己捕获任何错误。done()

喜欢这个:

it('should transition with the correct event', () => {
  ...
  return new Promise((resolve, reject) => {
    ...
  }).then((state) => {
    assert(state.action === 'DONE', 'should change state');
  })
  .catch((error) => {
    assert.isNotOk(error,'Promise error');
  });
});

答案 2

对于那些在测试环境之外寻找错误/警告的人来说,这可能是因为代码中没有人处理承诺中的最终错误:UnhandledPromiseRejectionWarning

例如,此代码将显示此问题中报告的警告:

new Promise((resolve, reject) => {
  return reject('Error reason!');
});

(node:XXXX) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Error reason!

添加或处理错误应该解决警告/错误.catch()

new Promise((resolve, reject) => {
  return reject('Error reason!');
}).catch(() => { /* do whatever you want here */ });

或者在函数中使用第二个参数then

new Promise((resolve, reject) => {
  return reject('Error reason!');
}).then(null, () => { /* do whatever you want here */ });