Jasmine: Testing AJAX calls that manipulate the DOM
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)
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
/usersand 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'
- We need a
<div class="users">...</div>containers for the code to work on. We're using jasmine-fixture 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
itblock. We are calling
done()once the response has been received and observed by the test.
- We're using jasmine-ajax 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
- We're using jasmine-jquery to get some DOM-related matchers like
See Jasmine: Mocking API requests in an Angular service spec on how to do similar things in an Angular application.