dman
dman

Reputation: 11064

Test will not call done() when failing

I am writing a unit test to test my postgres schema. I am using node-pg, mocha, sinon, and chai.

This works - the test passes with no issues:

describe('When adding a user', ()=> {
  it('should reject since email is used somewhere else', (done)=> {
    pool.query(`INSERT INTO users(email, id, token)
               VALUES($1, $2, $3)`, ['[email protected]', '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();
    })
  })
});

But to make sure I am not getting a false positive, I change the assert to result.constraint.should.not.have.string('email_already_exists'); to purposely make the test fail.

Instead of the test failing, I get Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test..

What am I getting this?

Upvotes: 0

Views: 287

Answers (2)

YSK
YSK

Reputation: 1614

If you would still like to use Promises for this, the problem is that unhandled exceptions in Promises are unfortunately not propagated but rather are silently ignored. As a result, no one calls Mocha's done method, leading to the timeout.

Attaching a listener to Node's unhandledRejection event as documented here should demonstrate this.

If you modify your original code and add a call to the Promise's done method (this isn't Mocha's done method!), then you'll be able to catch all errors and pass them to Mocha's done method:

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

Note that Promise.done() isn't (yet) part of the standard, but is nonetheless supported by many implementations. See for example here.

Upvotes: 3

dman
dman

Reputation: 11064

Answer:

The promise chain for node-pg causes this strange issue during testing. If I work off of callback, then no issue:

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($1, $2, $3)`, ['[email protected]', '12346', 'fooToken'], callback)
  })
});

Upvotes: 0

Related Questions