Properly call mocha done callback and promises - javascript

I have several integration tests in my app:
it('creating vehicle', function (done) {
createVehicle()
.then(() => {
done();
})
.catch((err) => {
done(err);
});
});
createVehicle makes post request and returns promise:
return request.json('post', '/api/vehicle/')
.send(obj)
.expect(200)
.then((res) => {
expect(res.body).toExist("Body is empty");
expect(res.body.id).toExist("Id is empty");
return res.body;
});
Now all works fine, but if I rewrite first snippet in the following way:
it('creating vehicle', function (done) {
createVehicle()
.then(done) //*
.catch(done); //*
});
I get error from Mocha
done() invoked with non-Error
I understand why. The createVehicle return res.body and it's passed to then callback, in result done run as done(arg) and I get the error, because mocha done callback has to be called without arg when there is no error and with argument when there is error.
Is it possible to use this variant:
.then(done)
.catch(done);
How to achieve this?
Of course, I can delete return statement, but createVehicle is used in several places and I need returned value:
it('creating vehicle with media', function (done) {
createVehicle()
.then(createMedia) //createMedia will get returned value
//....
});

The easiest solution would be to just return the promise instead of having to deal with callbacks, because Mocha supports promises out-of-the-box:
it('creating vehicle', function() {
return createVehicle();
});

Related

How to checking function called in Promise by sinon

I was using mocha + chai + sinon to test function, but in promise use called property, even if write a undefined function, called always true, What is it caused by ?and how to resolve? thx
describe("when click get verifycode", function () {
it('if get server response success, should start countdown', function (done) {
// given
sandbox.stub(model, 'getVerifyCode').resolves({});
sandbox.spy(view, 'startCountDown');
// when
var result = instance.onClickVerify('123456');
// then
result.then(res => {
// no matter what function, called always true
// e.g. expect(AnUndefinedFunction.called).to.be.ok;
expect(instance.view.startCountDown.called).to.be.ok;
done();
}).catch(err => {
done();
});
The problem here is that the .catch block is catching any error that occurs in the .then block.
This is an issue because you are calling done without passing the err object. Mocha interprets this as the test passing correctly, rather than failing.
The fix:
describe("when click get verifycode", function () {
it('if get server response success, should start countdown', function (done) {
// given
sandbox.stub(model, 'getVerifyCode').resolves({});
sandbox.spy(view, 'startCountDown');
// when
var result = instance.onClickVerify('123456');
// then
result.then(res => {
// no matter what function, called always true
// e.g. expect(AnUndefinedFunction.called).to.be.ok;
expect(instance.view.startCountDown.called).to.be.ok;
done();
}).catch(err => {
done(err);
});
})
});

How to get asserts in mocha before blocks to work?

How to get asserts in mocha before blocks to work? If I am not suppose to do this let me know. Currently, using promises, if I get an error using an catch block, I'll add an assert to fail the before block. WHat I want is it to fail the describe block, but instead I get two possible outcomes. 1. My test suite completely crashes, 2. I have to wait for each timeout to hit for each test because the before block failed.
before(function (done) {
promise()
.then(function () {
done();
})
.catch(function (error) {
assert(!error);
done();
});
});
I even tried this, thinking, maybe the done was never called.
before(function (done) {
promise()
.then(function () {
//no done here
})
.catch(function (error) {
assert(!error);
});
.finally(function () {
done();
});
});
So far to avoid crashing and waiting, and to make it work, I have done this:
var beforeError;
before(function (done) {
promise()
.then(function () {
done();
})
.catch(function (error) {
beforeError = error;
done();
});
});
it('test something', function () {
assert(beforeError, 'Before block failed with error.');
});
I am really curious if there is a better way to go about this so that if my before/beforeEach/after/afterEach blocks fail, it doesn't cause me to wait ages or my suite to crash! Thanks S/O community! :)
I can't speak to your use of the done callback, but mocha 3.0 supports promises in before hooks now. Were I to write this, I would let the returned promise throw its own error, which will fail the before hook without breaking the suite.
before(function () {
return promise(<async behavior here>);
});

How to 'reverse' the rejection/fulfillment of a promise?

For a mocha test, I want to assert that a promise will eventually reject.
I don't want to use chai-as-promised. I'd prefer to just use Node's standard assert module, and to just use standard ES6 promises.
The best I've come up with is this, but it feels slightly hacky:
it('foo should reject given bad data', function () {
var rejected;
return foo('bad data').catch(function (err) {
rejected = true;
}).then(function () {
assert(rejected);
});
});
Can anyone suggest a neater, more expressive way to 'reverse' a promise, so rejection becomes fulfillment and vice versa?
You could just assert on both the resolution and rejection callbacks passing true or false directly.
it('foo should reject given bad data', function () {
return foo('bad data').then(function () {
assert(false);
}, function () {
assert(true);
});
});
You could do it using a single .done() like so:
it('foo should reject given bad data', function () {
return foo('bad data')
.done(assert.equal.bind(null, 'false', 'true', null), assert);
});
I've used values for assert.equal that will provide the equivalent of assert(false), but you can obviously remove the last null if you want to print the actual result.
Edit: You could actually make this cleaner for multiple tests by defining your own assertFail function:
function assertFail () { assert(false); }
it('foo should reject given bad data', function () {
return foo('bad data')
.done(assertFail, assert);
});
You may add a reverse method to Promise prototype and then just use it.
Promise.prototype.reverse = function() {
return new Promise((resolve, reject) => {
this.then(reject).catch(resolve);
});
}
foo('bad data')
.reverse()
.then(e => assert(true))
.catch(e => assert(false));

Efficiently composing promise tests

I find myself often writing tests for async APIs like this:
beforeEach(function(done) {
setup()
.then(function(val) {
return setup2();
})
.done(done, done);
});
it('should test something', function(done) {
promiseFunction
.then(function(val) {
expect(val).to.be.something;
})
.done(done, done);
});
Which seems pretty straightforward, except for the beforeEach function: if setup2 returns a promise, then done will be called with a value, which it doesn't like. So I end up having to write:
.done(function() { done(); }, done)
which is all well and good, but I'm wondering if there's a more compact way to do this (yes, I'm lazy!). Like
.catch(done) //handle fail
.then(null) //strip the promise value
.then(done) //handle success
but then requires a function. I know a trivial solution is to write myself another function:
function noParam(done) { done(); }
and use:
.done(noParam(done), done);
I'm just wondering if there's a better way to compose this generally or a way to use existing API functions.
If done uses node callback conventions, you'll want to have a look at the .asCallback method. You might do
beforeEach(function(done) {
setup()
.then(function(val) {
return setup2();
})
.asCallback(done);
});
And mocha (unless you are using very old version) supports returning promises so your test code can be written as:
it('should test something', function() {
return promiseFunction
.then(function(val) {
expect(val).to.be.something;
});
});

ES6 Promises in Mocha

I'm using this polyfill for ES6 promises and Mocha / Chai.
My assertions for the promises are not working. The following is a sample test:
it('should fail', function(done) {
new Promise(function(resolve, reject) {
resolve(false);
}).then(function(result) {
assert.equal(result, true);
done();
}).catch(function(err) {
console.log(err);
});
});
When I run this test it fails due to timeout. The assertion failure that was thrown in the then block is caught in the catch block. How can I avoid this and just throw it straight to Mocha?
I could just throw it from the catch function, but then how would I make assertions for the catch block?
If your Promise has a failure, it will only call your catch callback. As a result, Mocha's done callback is never called, and Mocha never figures out that the Promise failed (so it waits and eventually times out).
You should replace console.log(err); with done(err);. Mocha should automatically display the error message when you pass an error to the done callback.
I ended up solving my problem by using Chai as Promised.
It allows you to make assertions about the resolution and rejections of promises:
return promise.should.become(value)
return promise.should.be.rejected
A pattern I use in my Mocha/Chai/es6-promise tests is the following:
it('should do something', function () {
aPromiseReturningMethod(arg1, arg2)
.then(function (response) {
expect(response.someField).to.equal("Some value")
})
.then(function () {
return anotherPromiseReturningMethod(arg1, arg2)
})
.then(function (response) {
expect(response.something).to.equal("something")
})
.then(done).catch(done)
})
The last line is odd looking, but calls Mocha's done on success or on error.
One problem is if the last then returns something, I then need to noop()* before both the then and the catch:
it('should do something', function () {
aPromiseReturningMethod(arg1, arg2)
.then(function (response) {
expect(response.someField).to.equal("Some value")
})
.then(function () {
return anotherPromiseReturningMethod(arg1, arg2)
})
.then(_.noop).then(done).catch(done)
})
*Lodash's noop().
Would love to hear any critiques of this pattern.

Categories

Resources