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) ->
    $('.users').html(html)
Illustration UI/UX Design

UI/UX Design by makandra brand

We make sure that your target audience has the best possible experience with your digital product. You get:

  • Design tailored to your audience
  • Proven processes customized to your needs
  • An expert team of experienced designers
Read more Show archive.org 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
    jasmine.Ajax.install()

    # 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
      done()

    # Fetch the last AJAX request for inspection
    request = jasmine.Ajax.requests.mostRecent()
    expect(request.url).toMatch(/\/users$/)
    expect(request.method).toBe('GET')
    
    # Fake the response
    request.respondWith
      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 archive.org 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 archive.org 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 archive.org 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)