When I'm testing with Mocha, I often have a combination of both asynchronous and synchronous tests that need to run.
Mocha handles this beautifully allowing me to specify a callback, done
, whenever my tests are asynchronous.
My question is, how does Mocha internally observe my tests and know that it should wait for asynchronous activity? It seems to wait anytime I have the callback parameter defined in my test functions. You can see in the examples below, the first test should timeout, the second should proceed and finish before user.save
calls the anonymous function.
// In an async test that doesn't call done, mocha will timeout.
describe('User', function(){
describe('#save()', function(){
it('should save without error', function(done){
var user = new User('Luna');
user.save(function(err){
if (err) throw err;
});
})
})
})
// The same test without done will proceed without timing out.
describe('User', function(){
describe('#save()', function(){
it('should save without error', function(){
var user = new User('Luna');
user.save(function(err){
if (err) throw err;
});
})
})
})
Is this node.js specific magic? Is this something that can be done in any Javascript?
Writing Asynchronous Tests with Mocha. To indicate that a test is asynchronous in Mocha, you simply pass a callback as the first argument to the it() method: it('should be asynchronous', function(done) { setTimeout(function() { done(); }, 500); });
According to it, tests are run synchronously. This only shows that ordered code is run in order. That doesn't happen by accident.
Mocha does not run individual tests in parallel. If you only have one test file, you'll be penalized for using parallel mode.
In case anyone is interested, most IDEs also allow you to inject mocha options for test execution; e.g. for WebStorm, you can enter this (i.e. "--timeout 10000") under Run->Edit Configurations->Extra Mocha Options.
This is simple pure Javascript magic.
Functions are in fact objects, and they have properties (such as the number of parameters are defined with the function).
Look at how this.async is set in mocha/lib/runnable.js
function Runnable(title, fn) {
this.title = title;
this.fn = fn;
this.async = fn && fn.length;
this.sync = ! this.async;
this._timeout = 2000;
this._slow = 75;
this.timedOut = false;
}
Mocha's logic changes based whether or not your function is defined with parameters.
What you're looking for is Function's length property which can tell how many arguments a function is expecting. When you define a callback with done
it can tell and treats it asynchonously.
function it(str, cb){
if(cb.length > 0)
//async
else
//sync
}
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/Length
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