0

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)`, ['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();
    })
  })
});

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?

dman
  • 10,406
  • 18
  • 102
  • 201
  • 1
    If you're testing promise-based code, you should consider using Mocha's built-in [promises support](https://mochajs.org/#working-with-promises). Much easier to prevent issues like this. – robertklep May 06 '17 at 06:14
  • @robertklep How could this promise support be used in testing 2 fetches in node? http://stackoverflow.com/questions/43690868/how-to-assert-stubbed-fetch-more-than-once/43806205#43806205 – dman May 06 '17 at 15:22
  • 1
    A good example: https://coderwall.com/p/axugwa/cleaning-the-database-in-between-mocha-tests-with-pg-promise – vitaly-t May 06 '17 at 15:41
  • 1
    @dman in that question, you're starting with code that doesn't test well to begin with. For instance, `index.js` runs code that isn't exposed in any way to the "outside world". – robertklep May 06 '17 at 16:28
  • @robertklep that crossed my mind, since only `function a` is public. Since `function a` just does work does not return anything, how can I assert it does it work(in this case fetch) according to it's if then conditions inside? – dman May 06 '17 at 17:29
  • 1
    @dman see [this gist](https://gist.github.com/robertklep/4e5e8543aa6e11b59c9c4bc6210af112). – robertklep May 06 '17 at 17:47
  • @robertklep woe! Thank you so much!!!! I was so close...never thought of using `promises.then()`. This made my weekend...thanks again! – dman May 07 '17 at 01:49

2 Answers2

3

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.

YSK
  • 1,572
  • 10
  • 19
0

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)`, ['foo@email.com', '12346', 'fooToken'], callback)
  })
});
dman
  • 10,406
  • 18
  • 102
  • 201