Mocking AJAX requests with Jasmine

Following on from Getting started with jasmine tests and Django, in this post we will be concentrating on how you can fake your AJAX posts in your Jasmine tests. This tutorial will just cover enough to get you started ...

The code for this tutorial can be found here:
https://github.com/toast38coza/jasmine-django-tutorial/releases/tag/tut-2

Getting started.

First things first, we need to install the 'jasmine-ajax' helper.

If we look in our jasmine.yml file, we will notice that it has a helpers directory:

helpers:
  - helpers/**/*.js"    

We need to add the jasmine-ajax helper here:

From the directory with manage.py:

mkdir -p spec/javascripts/helpers
cd spec/javascripts/helpers
curl https://raw.githubusercontent.com/pivotal/jasmine-ajax/master/lib/mock-ajax.js > mock-ajax.js

Now, let's update our tests. Add the following to hello_spec.js within the describe statement where we want to stub the AJAX

beforeEach(function() {
  jasmine.Ajax.install();
});

afterEach(function() {
  jasmine.Ajax.uninstall();
});

All this is doing is installing the AJAX plugin, but stop and start the jasmine server and navigate to 127.0.0.1:8888 and you should still see that our tests are running. We haven't actually done any mocking yet, but at least we know our tests are running!

Now. Let's mock some AJAX:

At the following test to hello_spec:

it ("Logs text from the service to the console", function () {

  var consoleSpy = spyOn(console, "log");

  jasmine.Ajax.stubRequest('/some/url').andReturn({
    "status": 200, 
    "contentType": 'text/plain',
    "responseText": 'Hello from the world'
  });

  var result = Hello.callWorld();
  expect(consoleSpy).toHaveBeenCalledWith('Hello from the world');
});

This will fail (like we expect it to) .. now, let's make it pass. Add the following to hello.js

callWorld : function () {
    var xhr = $.ajax('/some/url')
        .done(function(responseText) { 
            console.log( responseText ); 
        })
          .fail(function() { 
              console.log( "error" ); 
          })
          .always(function() { 
              console.log( "complete" ); 
          });
}

run the tests .. and it will tell us:

ReferenceError: $ is not defined

Right .. we need to install jquery .. we'll use bower for that:

 cd static
 bower install jquery

now we have bower_components/jquery/**. Let's add that to our setup in jasmine.yml, edit src_files like so:

src_files: 
  - "bower_components/jquery/jquery.min.js"
  - "js/*.js"

Note: for some reason my configuration complained if I didn't use the "s

Run it again, and it should pass:

2 specs, 0 failures

  • Test hello.js
    • return 'hello'
    • Logs text from the service to the console

Great. Now, let's quickly add a test for the negative case. Add the following test:

it ("Prints error if the service fails", function () {

    var consoleSpy = spyOn(console, "log");

    jasmine.Ajax.stubRequest('/some/url').andReturn({
    "status": 500, 
    "contentType": 'text/plain'
  });

    var result = Hello.callWorld();
    expect(consoleSpy).toHaveBeenCalledWith("error");

});

All we've really done here is change the status code returned to 500. Now we can easily test the negative case as well.

Finally, we also want to exercise .always(). We can add the following expectation to box tests:

expect(consoleSpy).toHaveBeenCalledWith("complete");

And we're done. A quick intro to testing AJAX calls with Jasmine. To recap we:

  • Installed the jasmine-ajax helper
  • Mocked an AJAX call
  • Verified it's behaviour using a Spy