How To Test Asynchronous Javascript Functions Using Jasmine

Testing asynchronous JavaScript function calls with Jasmine came be tricky to understand at first. I have searched forums and blogs and what I have found is a lot of confusion. The following article describes in detail how to test asynchronous JavaScript functions using Jasmine.

The Jasmine documentation for asynchronous support can be found here. Read the five or so paragraphs provided. Look at the example code then come back and I’ll provide an in-depth explanation. Seriously, go read it. It is important. Go on… Thanks.

I’m assuming their example to the right of the description is what is causing people some trouble. I had to read it several times before I understood exactly what they were doing.


Our Goal

Stop thinking about code for a minute. Let’s take a look at this from a high level. You want to create a new test suite that will contain one or more unit tests. At least one of those unit tests will need to call an asynchronous function. The asynchronous fuction will run and eventually succeed or fail. We then need to test the results of the success or failure with the facilities provided in Jasmine.

Break It Down

Let us break this problem down into individual peices that can be easily understood. We are going to look at writing just one single unit test. That unit test will contain three major sections.

Unit Test – Section 1

The first section will make an asynchronous call and provide a callback for success, and a callback for failure. In our example we will use an ajax call using jQuery.

Unit Test – Section 2

The second section of the unit test basically makes the unit test hang out and wait until some sort of event occurs. So, how long do you want to wait for? You want to wait until the asynchronous call completes. It doesn’t matter if the asynchronous call was successful or not, we need to wait until it completes. How do you know when the asynchronous call is complete? The asynchronous call is complete when the success or failure callback is called. Given that, you should now understand that section two is going to wait on a flag that will be have to be set by either the success or failure callback.

Unit Test – Section 3

The third section is where you write all your tests. It is reasonable to assume you want run tests on the result set from the asynchronous call. This means you are going to have to store the result set somewhere during the success callback or failure callback.


Implementation Details

The runs() function is going to be used twice. It is going to wrap the code in section 1 and section 3. Section 1, calls the asynchronous function. Section 3 will perform the individual tests on a result set.

Section 2 is going to use the waitsFor() function. waitsfor() is a function that waits for a trigger. So, typically at the start of your test you will define a local variable to false or null. In the success and failure callbacks for the asynchronous function in section 1, you set the trigger to a new value. The waitsFor() function will wait for the variable to stop being false, or stop being null, depending on which route you need to take.

Example Code

I prefer to code in CoffeeScript than JavaScript, so I provided an example solution using both languages. The examples can can be found below.


CoffeeScript Example

  
it "can perform a successful ajax request on resource blah.html", ->

  # asyncCallComplete is set to true when the ajax call is complete
  asyncCallComplete = false

  # result stores the result of the successful ajax call
  result = null

  # SECTION 1 - call asynchronous function
  runs =>
    $.ajax '/blah.html',
      type: 'GET',
      success: (data) =>
        asyncCallComplete = true
        result = data
        return

      error: =>
        asyncCallComplete = true
        return

  # SECTION 2 - wait for the asynchronous call to complete
  waitsFor =>
    return asyncCallComplete != false

  # SECTION 3 - perform tests
  runs =>
    # the ajax result should no longer be null
    expect(result).not.toBeNull()
  

JavaScript Example

  
it("can perform a successful ajax request on resource blah.html", function() {
  var asyncCallComplete, result,
    _this = this;
  // asyncCallComplete is set to true when the ajax call is complete
  asyncCallComplete = false;

  // result stores the result of the successful ajax call
  result = null;

  // SECTION 1 - call asynchronous function
  runs(function() {
    return $.ajax('/blah.html', {
      type: 'GET',
      success: function(data) {
        asyncCallComplete = true;
        result = data;
      },
      error: function() {
        asyncCallComplete = true;
      }
    });
  });

  // SECTION 2 - wait for the asynchronous call to complete
  waitsFor(function() {
    return asyncCallComplete !== false;
  });

  // SECTION 3 - perform tests
  return runs(function() {
    return expect(result).not.toBeNull();
  });
});
  

2 thoughts on “How To Test Asynchronous Javascript Functions Using Jasmine

  1. Dev

    I’m getting ReferenceError: $ is not defined. what could be the issue?

    I have installed jasmine. and normal spec are running properly.

    Reply

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>