Paul English
Paul English

Reputation: 937

How does Mocha know to wait and timeout only with my asynchronous tests?

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?

Upvotes: 15

Views: 4168

Answers (2)

supershabam
supershabam

Reputation: 706

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.

Upvotes: 22

George
George

Reputation: 437

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

Upvotes: 4

Related Questions