Read more

Jasmine: Testing AJAX calls that manipulate the DOM

Henning Koch
January 17, 2015Software engineer at makandra GmbH

We no longer use jQuery and CoffeeScript

Here is a Javascript function reloadUsers() that fetches a HTML snippet from the server using AJAX and replaces the current .users container in the DOM:

window.reloadUsers = ->
  $.get('/users').then (html) ->
Illustration money motivation

Opscomplete powered by makandra brand

Save money by migrating from AWS to our fully managed hosting in Germany.

  • Trusted by over 100 customers
  • Ready to use with Ruby, Node.js, PHP
  • Proactive management by operations experts
Read more Show snapshot

Testing this simple function poses a number of challenges:

  • It only works if there is a <div class="users">...</div> container in the current DOM. Obviously the Jasmine spec runner has no such container.
  • The code requests /users and we want to prevent network interaction in our unit test.
  • The AJAX call is asynchronously and we don't have control over when it returns (and hence when it calls the callback function).

Here is a test that does all that:

describe 'reloadUsers', ->

  it 'replaces the user list with a fresh copy from /users', (done) ->

    # Mock network connections

    # Create the DOM elements the code works on
    affix('.users').text('old is')

    reloadUsers().then ->
      # Observe the result of the function
      expect('.users').toHaveText('new users')
      # Tell Jasmine that the example is over

    # Fetch the last AJAX request for inspection
    request = jasmine.Ajax.requests.mostRecent()
    # Fake the response
      status: 200
      contentType: 'text/html'
      responseText: 'new users'

Some notes:

  • We need a <div class="users">...</div> containers for the code to work on. We're using jasmine-fixture Show snapshot to quickly create such a container from a CSS selector by saying affix('.users'). jasmine-fixture will append the container to the document body and clean it up after the test.
  • We need to tell Jasmine to wait until the AJAX response was processed. We do this by accepting an argument done from the it block. We are calling done() once the response has been received and observed by the test.
  • We're using jasmine-ajax Show snapshot to mock access to the network. jasmine.Ajax.requests.mostRecent() returns the most recent AJAX request, which we can inspect for its parameters and payload. We can also trigger a fake response by calling request.respondWith(...).
  • We're using jasmine-jquery Show snapshot to get some DOM-related matchers like haveText(...).

See Jasmine: Mocking API requests in an Angular service spec on how to do similar things in an Angular application.

Posted by Henning Koch to makandra dev (2015-01-17 19:42)