SHARE
Facebook X Pinterest WhatsApp

Using the done() Method in Your Jasmine-driven Asynchronous JavaScript Tests

Written By
thumbnail
Rob Gravelle
Rob Gravelle
Jun 20, 2013

Using the done() Method in Your Jasmine-driven Asynchronous JavaScript Tests

6/19/13

Jasmine.Async is an add-on library for Jasmine that provides additional functionality to do asynchronous testing. Modeled after Mocha’s async test support, it brings the done() function to the Jasmine unit testing environment. In today’s article, we’ll learn how the Jasmine.Async library makes your asynchronous process tests easier to write.

A Little History

Derick Bailey, the Jasmine.Async author, is a big fan of Jasmine, but noticed that making Jasmine work with asynchronous JavaScript was less than ideal. In particular, he didn’t like how runs() and waitsFor() calls were repeated every time you needed to wait for an asynchronous process to complete.

Thus, the Jasmine.Async library was born by borrowing Mocha’s use of the done() when the asynchronous code has completed.

How It Works

In my Test Asynchronous Methods Using the Jasmine runs() and waitFor() Methods article, I discussed the Jasmine runs() and waitFor() methods, which were created especially for the purpose of the practical implementation of asynchronous processes such as Ajax. Nonetheless, the runs() and waitFor() methods are equally adept at testing simulated asynchronous calls using the setTimeout(),setInterval(), or various event handlers.

Case in point, the following test employs setTimeout() to create an asynchronous event that takes 500 milliseconds to complete. An initial runs() call sets the default variables and makes the call to setTimeout(). Then the waitsFor() method causes intermittently returns the value of a flag to the Jasmine framework so that it knows when to continue execution of the test. Once the flag has been set to true, the second runs() method verifies our expectations:

describe("async tests", function(){
 var flag, value;
 it("should simulate an asynchronous call", function () { 
  runs(function() { 
    flag  = false; 
    value = 0; 
  
    setTimeout(function() { 
      value++; 
      flag = true; 
    }, 500); 
  });  
  
  waitsFor(function() { 
    return flag; 
  }, "The Value should be incremented", 5000);  

  runs(function() {  
    expect(flag).toEqual(true);   
    expect(value).toEqual(1); 
  }); 
 }); 
}); 

Contrast the above test to the equivalent one below, using the Jasmine.Async library:

describe("async tests", function(){   
  var flag,     
      value, 
      async = new AsyncSpec(this);   
  
  async.beforeEach(function(done){    
    flag  = false;
    value = 0;
    // simulate async stuff and wait 500ms    
    setTimeout(function(){      
      flag = true;  
      value++;    
      done();    
    }, 500);    
  });   
  
  async.it("should simulate an asynchronous call", function(){      
    expect(flag).toBe(true);  
    expect(value).toEqual(1);
  }); 
});

The primary feature of the Jasmine.Async test is the call to the done() function that tells Jasmine that the process has completed. This approach negates the need for the waitsFor() method. In Mocha, if the process hasn’t come back done or failed an assertion in a certain amount of time (the default is 2000ms), the test fails. Jasmine.Async relies on Jasmine’s timeout of 5 seconds, as the following error confirms:

timeout: timed out after 5000 msec waiting for something to happen

Multiple Asynchronous Operations

You can include as many asynchronous operations as you wish, so long as you always call the done() method afterwards. The assertions won’t run until all of the processes have come back or timed out:

function  doSomething() {
  console.log('doSomething()...');
}

function  doSomethingElse() {
  console.log('doSomethingElse()...');
}
    
describe("an async spec", function(){

  // set up the async spec
  var async = new AsyncSpec(this);

  // run an async setup
  async.beforeEach(function(done){
    console.log('beforeEach()...');
    doSomething();

    // simulate async stuff and wait 1 sec
    setTimeout(function(){
      // more code here
      doSomethingElse();
      // when the async process is done, call done()
      done();
    }, 1000); 
  });

  // run an async cleanup
  async.afterEach(function(done){
    // simulate async cleanup
    setTimeout(function(){
      done();
      console.log('afterEach()');
    }, 1000);
  });

  // run an async expectation
  async.it("did stuff", function(done){
    // simulate additional async code
    setTimeout(function(){
      expect(1).toBe(1);
      // all async calls completed
      done();
      console.log( 'done.' );
    }, 1000);    
  });
});

Outputting some text to the console helps verify that each timeout() call is taking about one second each. Notice that even the assertion has a timeout!

Let’s take things a step further by introducing an additional expectation. That will cause the beforeEach() and afterEach() to fire twice – once for each expectation – as well as perform an extra increment operation on the value variable. Here’s the code:

describe("spec for multiple async calls", function(){
  // set up the async spec
  var value = 0,
      async = new AsyncSpec(this);

  // run an async setup
  async.beforeEach(function(done){
    setTimeout(function(){
      console.log( 'beforeEach()...');
      value++;
      done();
    }, 1000);
  });

  // run an async cleanup
  async.afterEach(function(done){
    // simulate async cleanup
    setTimeout(function(){
      done();
      console.log( 'afterEach()');
    }, 1000);
  });

  async.it("expectations for async call one", function(done){
    setTimeout(function(){
      console.log( 'checking expectation.' );  
      expect(value).toEqual(1);
      done();
      console.log( 'done.' );
    }, 1000);  
  });
  
  async.it("expectations for async call two", function(done){
    setTimeout(function(){
      console.log( 'checking expectation.' );  
      expect(value).toEqual(2);
      done();
      console.log( 'done again.' );
    }, 1000);    
  });
});

Thanks to the console.log() calls, we can see exactly what occurred during the test run:

Conclusion

The Jasmine.Async library adds the goodness of Mocha’s done() method to your asynchronous process tests. Use the jasmine.async.js file in development and jasmine.async.min.js in your production environment. The latter is a mere 1 KB! Just drop the appropriate script file in the same folder as your Jasmine scripts and link to it in your Test Runner HTML page.

Recommended for you...

The Revolutionary ES6 Rest and Spread Operators
Rob Gravelle
Aug 23, 2022
Ahead of Time (AOT) Compilation in Angular
Tariq Siddiqui
Aug 16, 2022
Converting a JavaScript Object to a String
Rob Gravelle
Aug 14, 2022
Understanding Primitive Type Coercion in JavaScript
Rob Gravelle
Jul 28, 2022
HTML Goodies Logo

The original home of HTML tutorials. HTMLGoodies is a website dedicated to publishing tutorials that cover every aspect of being a web developer. We cover programming and web development tutorials on languages and technologies such as HTML, JavaScript, and CSS. In addition, our articles cover web frameworks like Angular and React.JS, as well as popular Content Management Systems (CMS) that include WordPress, Drupal, and Joomla. Website development platforms like Shopify, Squarespace, and Wix are also featured. Topics related to solid web design and Internet Marketing also find a home on HTMLGoodies, as we discuss UX/UI Design, Search Engine Optimization (SEO), and web dev best practices.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.