How can I execute async Mocha tests (NodeJS) in order?


Question

This question relates to the Mocha testing framework for NodeJS.

The default behaviour seems to be to start all the tests, then process the async callbacks as they come in.

When running async tests, I would like to run each test after the async part of the one before has been called.

How can I do this?

1
50
4/28/2014 11:30:18 AM

Accepted Answer

The point is not so much that "structured code runs in the order you've structured it" (amaze!) - but rather as @chrisdew suggests, the return orders for async tests cannot be guaranteed. To restate the problem - tests that are further down the (synchronous execution) chain cannot guarantee that required conditions, set by async tests, will be ready they by the time they run.

So if you are requiring certain conditions to be set in the first tests (like a login token or similar), you have to use hooks like before() that test those conditions are set before proceeding.

Wrap the dependent tests in a block and run an async before hook on them (notice the 'done' in the before block):

var someCondition = false

// ... your Async tests setting conditions go up here...

describe('is dependent on someCondition', function(){

  // Polls `someCondition` every 1s
  var check = function(done) {
    if (someCondition) done();
    else setTimeout( function(){ check(done) }, 1000 );
  }

  before(function( done ){
    check( done );
  });

  it('should get here ONLY once someCondition is true', function(){ 
    // Only gets here once `someCondition` is satisfied
  });

})
35
6/6/2013 7:19:09 AM

I'm surprised by what you wrote as I use. I use mocha with bdd style tests (describe/it), and just added some console.logs to my tests to see if your claims hold with my case, but seemingly they don't.

Here is the code fragment that I've used to see the order of "end1" and "start1". They were properly ordered.

describe('Characters start a work', function(){
    before(function(){
      sinon.stub(statusapp, 'create_message');
    });
    after(function(){
      statusapp.create_message.restore();
    });
    it('creates the events and sends out a message', function(done){
      draftwork.start_job(function(err, work){
        statusapp.create_message.callCount.should.equal(1);
        draftwork.get('events').length.should.equal(
          statusapp.module('jobs').Jobs.get(draftwork.get('job_id')).get('nbr_events')
        );
        console.log('end1');
        done();
      });
    });
    it('triggers work:start event', function(done){
      console.log('start2');
      statusapp.app.bind('work:start', function(work){
        work.id.should.equal(draftwork.id);
        statusapp.app.off('work:start');
        done();
      });

Of course, this could have happened by accident too, but I have plenty of tests, and if they would run in parallel, I would definitely have race conditions, that I don't have.

Please, refer to this issue too from the mocha issue tracker. According to it, tests are run synchronously.


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon