0

I'm having a hard time getting meaningful failures in tests when I need to check things in a promise.

That's because most testing frameworks use throw when an assertion fails, but those are absorbed by the then of promises...

For example, in the following I'd like Mocha to tell me that 'hello' isn't equal to 'world'...

Promise.resolve(42).then(function() {
  "hello".should.equal("world") 
})

Complete fiddle here

With Mocha we can officially return the promise, but this swallows completely the error and is thus much worse...

Note: I'm using mocha and expect.js (as I want to be compatible with IE8)

Marc-André Lafortune
  • 78,216
  • 16
  • 166
  • 166

3 Answers3

1

With Mocha we can officially return the promise, but this swallows completely the error and is thus much worse...

In your fiddle, you are using Mocha 1.9 which dates from April 2013, and did not support returning promises from tests. If I upgrade your fiddle to the latest Mocha, it works just fine.

Louis
  • 146,715
  • 28
  • 274
  • 320
  • You can return a Promise to test for resolution. You can't just return a Promise when testing rejection because your test will incorrectly pass if there is an error in your code that causes the Promise to unexpectedly resolve. – Andrew Eddie Jun 08 '16 at 22:06
  • Well, what you are saying here amounts to tautologically saying "it is not going to work correctly if you write your code incorrectly". – Louis Jun 08 '16 at 22:11
  • Just returning the Promise **may** allow your test to **pass** incorrectly if you have written your code incorrectly. Your Promise always has a chance to resolve before it gets to the assertions in your `catch` when you are testing for rejection. Tautology or not, that's how it works. – Andrew Eddie Jun 08 '16 at 22:48
  • I understood what you said the first time around. There's absolutely no need for bolding anything. If you start with the unwarranted assumption that the solution won't be implemented correctly because that's what you decide to imagine, then the solution won't work. This is an objection you could bring up about all answers posted on SO. – Louis Jun 08 '16 at 22:52
  • Oh, I see what you mean. Yes, I'm deliberately trying to educate the author of the question beyond the actual scope of the question. – Andrew Eddie Jun 08 '16 at 23:26
0

This is less of an answer rather than a suggestion? Using the before hook would be useful here.

describe('my promise', () => {

  let result;
  let err;

  before(done => {
    someAsync()
      .then(res => result = res)
      .then(done)
      .catch(e => {
        err = e;
        done();
      });
  });

  it('should reject error', () => {
    err.should.not.be.undefined(); // I use chai so I'm not familiar with should-esque api
    assert.includes(err.stack, 'this particular method should throw')
  });

});

You could also use sinon to make synchronous mocks and then use whatever should.throw functionality your assertion library provides.

Daniel Lizik
  • 3,058
  • 2
  • 20
  • 42
-1

To test a failing Promise, do this:

it('gives unusable error message - async', function(done){
  // Set up something that will lead to a rejected promise.
  var test = Promise.reject(new Error('Should error'));

  test
    .then(function () {
      done('Expected promise to reject');
    })
    .catch(function (err) {
      assert.equal(err.message, 'Should error', 'should be the error I expect');
      done();
    })
    // Just in case we missed something.
    .catch(done);
});
Andrew Eddie
  • 988
  • 6
  • 15
  • You absolutely do *not* need to do this with Mocha. Just return the promise. – Louis Jun 08 '16 at 10:57
  • You can't just return the Promise because if your code accidentally resolves, Mocha will think your test passes and you get a false positive. You can leave the `.then` out above, but I included it to demonstrate what can go wrong when testing for Promise rejection. – Andrew Eddie Jun 08 '16 at 22:03
  • Of course, if start with the unwarranted assumption that all other solutions cannot be implemented correctly, then only your solution works. – Louis Jun 08 '16 at 22:15
  • It's not unwarranted. Testing Promise rejection is just not as easy as `assert.throws`. There are a couple of extra gotchas. – Andrew Eddie Jun 08 '16 at 22:49
  • Ok my apologies. You are technically right. He's not trying to trap a rejection. The fact that he's throwing an example error actually threw me into thinking he was. – Andrew Eddie Jun 09 '16 at 11:31