How should I be testing, with mocha and chai, that my promise has failed?
I am confused, because I initially thought I should be using 'mocha-as-promised', but that package is now deprecated (I'm using mocha 2.1.0), with the advice to just use the promise testing that's now built into mocha. see: https://github.com/domenic/mocha-as-promised
Another post recommends doing away with the 'done' argument to the it() callback - not sure I understand why, since my understanding that passing in the 'done' parameter was the way to signal that a test was being tested asynchronously. see: How do I properly test promises with mocha and chai?
Anyway, I've tried to reduce my issue to the below code - please help me modify this so that I can test that my promise indeed fails.
it.only("do something (negative test)", function (done) {
var Q = require('q');
function makePromise() {
var deferred = Q.defer();
deferred.reject(Error('fail'));
return deferred.promise;
};
makePromise()
.then(done, done);
});
chai-as-promised
provides a clean testing framework for Promises:
$ npm install chai-as-promised
In your test file:
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');
});
This feels clean and intuitive. But you can accomplish something similar without chai-as-promised like this:
it('resolved as promised', function() {
return Promise.resolve("woof")
.then(function(m) { expect(m).to.equal('woof'); })
.catch(function(m) { throw new Error('was not supposed to fail'); })
;
});
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'); })
;
});
You can return a promise to signal that the test is asynchronous:
function something() {
return Q.reject(Error('fail'));
}
it('should reject', function() {
return something().then(function() {
throw new Error('expected rejection');
},
function() {
return 'passed :]';
});
});
Some more digging, and it appears the right way is to add an additional catch block, like so...
it.only("do something (negative test)", function (done) {
var Q = require('q');
function makePromise() {
var deferred = Q.defer();
deferred.reject(Error('fail'));
return deferred.promise;
};
makePromise()
.catch(function(e) {
expect(e.message).to.equal('fail');
})
.then(done, done);
});
I'm interested in alternative ideas, or confirmation that this is fine the way it is.. thanks.
UPDATE:
Ben - I now grok what you were saying, esp. after the terse but helpful comment from Benjamin G.
To summarize:
When you pass in a done
parameter, the test is expected to trigger it's 'done-ness' by calling the done()
function;
When you don't pass in a done
parameter, it normally only works for synchronous calls. However,
if you return a promise, the mocha framework (mocha >1.18) will catch any failures that normally would have been swallowed (per the promises spec). Here is an updated version:
it.only("standalone neg test for mocha+promises", function () {
var Q = require('q');
function makePromise() {
var deferred = Q.defer();
deferred.reject(Error('fail'));
return deferred.promise;
};
return makePromise()
.catch(function(e) {
expect(e.message).to.equal('fail');
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With