Posted almost 6 years ago. Visible to the public. Repeats.

Jasmine: Testing AJAX calls that manipulate the DOM

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:

Copy
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 /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:

Copy
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 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 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 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.

Does your version of Ruby on Rails still receive security updates?
Rails LTS provides security patches for old versions of Ruby on Rails (3.2 and 2.3).

Owner of this card:

Avatar
Henning Koch
Last edit:
about 3 years ago
by Henning Koch
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Henning Koch to makandra dev
This website uses short-lived cookies to improve usability.
Accept or learn more