测试失败时不会调用 done()

Test will not call done() when failing

我正在编写单元测试来测试我的 postgres 架构。我正在使用 node-pg、mocha、sinon 和 chai。

这有效 - 测试顺利通过:

describe('When adding a user', ()=> {
  it('should reject since email is used somewhere else', (done)=> {
    pool.query(`INSERT INTO users(email, id, token)
               VALUES(, , )`, ['foo@email.com', '12346', 'fooToken'])
    .then((result)=> {
      console.log('nothing in here runs, you will not see this');
      done()
    })
    .catch((result) => {
      result.constraint.should.have.string('email_already_exists');
      done();
    })
  })
});

但是为了确保我没有得到误报,我将断言更改为 result.constraint.should.not.have.string('email_already_exists'); 以故意使测试失败。

我没有测试失败,而是 Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.

我得到了什么?

答案:

node-pg 的承诺链在 测试期间导致了这个奇怪的问题。如果我关闭回调,那么没问题:

describe('When adding a user', ()=> {
  it('should reject since email is used somewhere else', (done)=> {
    function callback(err, result) {
      err.constraint.should.not.have.string('email_already_exists');
      done();
    }
    pool.query(`INSERT INTO users(email, id, token)
               VALUES(, , )`, ['foo@email.com', '12346', 'fooToken'], callback)
  })
});

如果您仍想为此使用 Promises,问题是 Promises 中未处理的异常很遗憾不会传播,而是被静默忽略。结果没有人调用mocha的done方法,导致超时

按照记录 here 将侦听器附加到 Node 的 unhandledRejection 事件应该证明这一点。

如果您修改原始代码并添加对 Promise 的 done 方法的调用(这不是 Mocha 的 done 方法!),那么您将能够捕获所有错误并将它们传递给 Mocha 的 done 方法:

it('tests something', done => {
    pool.query('...')
    .then(result => {
        // ...
     })
    .catch(result => {
        // assertion that fails
    })
    .done(result => {}, error => { done(error); });
});

请注意,Promise.done()(目前)不是标准的一部分,但仍然受到许多实现的支持。例如参见 [​​=18=].