I have a class that rejects a promise:
Sync.prototype.doCall = function(verb, method, data) {
var self = this;
self.client = P.promisifyAll(new Client());
var res = this.queue.then(function() {
return self.client.callAsync(verb, method, data)
.then(function(res) {
return;
})
.catch(function(err) {
// This is what gets called in my test
return P.reject('Boo');
});
});
this.queue = res.delay(this.options.throttle * 1000);
return res;
};
Sync.prototype.sendNote = function(data) {
var self = this;
return self.doCall('POST', '/Invoice', {
Invoice: data
}).then(function(res) {
return data;
});
};
In my test:
return expect(s.sendNote(data)).to.eventually.be.rejectedWith('Boo');
However while the test passes it throws the error to the console.
Unhandled rejection Error: Boo
...
With non promise errors I have used bind to test to prevent the error from being thrown until Chai could wrap and test:
return expect(s.sendNote.bind(s, data)).to.eventually.be.rejectedWith('Boo');
However this does not work with this and returns:
TypeError: [Function] is not a thenable.
What is the correct way to test for this?
You're getting the error because sendNote is being rejected and you're not catching it.
Try:
var callPromise = self.doCall('POST', '/Invoice', {
Invoice: data
}).then(function(res) {
return data;
});
callPromise.catch(function(reason) {
console.info('sendNote failed with reason:', reason);
});
return callPromise;
Looks like you'll also have to move your existing catch one block out:
var res = this.queue.then(function() {
return self.client.callAsync(verb, method, data)
.then(function(res) {
return;
});
}).catch(function(err) {
// This is what gets called in my test
return P.reject('Boo');
});
(Disclaimer: This is a good question even for people that do not use Bluebird. I've posted a similar answer here; this answer will work for people that aren't using Bluebird.)
with chai-as-promised
Here's how you can use chai-as-promised to test both resolve
and reject
cases for a Promise:
var chai = require('chai');
var expect = chai.expect;
var chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);
...
it('resolves as promised', function() {
return expect(Promise.resolve('woof')).to.eventually.equal('woof');
});
it('rejects as promised', function() {
return expect(Promise.reject('caw')).to.be.rejectedWith('caw');
});
without chai-as-promised
You can accomplish the same without chai-as-promised like this:
it('resolves as promised', function() {
return Promise.resolve("woof")
.then(function(m) { expect(m).to.equal('woof'); })
.catch(function(e) { throw e }) // use error thrown by test suite
;
});
it('rejects as promised', function() {
return Promise.reject("caw")
.then(function(m) { throw new Error('was not supposed to succeed'); })
.catch(function(m) { expect(m).to.equal('caw'); })
;
});
I personally use that idiom:
it('rejects as promised', function() {
return Promise.reject("caw")
.then(
(m) => { assert.fail('was not supposed to succeed'); }
(m) => { /* some extra tests here */ }
);
});
This is one of the rare cases then(onFulfilled, onRejected)
(2 arguments) is legitimate to use.
If you chain .then(reject).catch(onRejected)
as suggested in other answers, you end up entering in the catch
handler every time since it will catch as well the rejection produced in the preceding then
handler--which could cause evergreen tests if you're not careful enough to check that eventuality.
I have faced the same problem but on doing many hacks I found a solution for testing rejected promises in mocha.
write mocha code as below
it('works with resolved and rejected promises', function() {
return yourPromiseFunction("paramifrequired")
.then((result)=>{
//check with should or expect
}).catch((result)=>{
//check with should or expect whether it's rejected with proper result status. set result status in promise function while rejecting accordingly
})
});
NOTE:- Hope you find it useful. If you have another idea suggestion do comment me I am newbie exploring the js world