We used Jasmine as our testing framework, but Jasmine by itself is not sufficient to cover asynchronous AJAX requests and DOM manipulation. We spent quite a lot of time navigating Stack Overflow responses and asking for help from coworkers, which led us to wrestle with jasmine-ajax and jasmine-jquery. Both of these plug-ins were significantly overpowered for what we were trying to test, and we got nowhere while trying to figure out how to use them correctly.
Luckily, my mentor got back from vacation, and I was able to pick his brain for assistance. He suggested using sinon and jasmine-fixture, which were both fairly simple libraries with documentation that was easy to decipher.
The first step was to separate the AJAX calls themselves from the DOM
manipulation. I set up my tests using
classes. I told the fake server to give a 200 status response to the type of
AJAX request I was testing and a spy to watch that the AJAX call was made and
Now to test the DOM manipulation. I had tried to set up HTML fixture files while
jasmine-jquery, but that seemed like a lot of redundant code
for testing functions that were pretty much just displaying or hiding elements
on a page. The
affix() function from
jasmine-fixture was much simpler,
allowing you to quickly set up the elements you needed to test, while also
taking care of cleaning them up after the test was run. I could create an
element, call my DOM manipulation function, then check to see that necessary
change had happened to the element.
These two steps allowed me to create a toolkit of reusable functions for making AJAX GET and POST requests and for displaying, hiding, and replacing parts of the DOM. Then I could easily write unit tests for the specific user interactions that combined those functions. Having the fake server here was especially useful because you could explicitly test that an element was loading the message body of the response received from the server after an AJAX request.
We are using Capybara to handle our
acceptance tests. While Capybara is very powerful, you do need to be thoughtful
about how you write any tests that cover functionality involving asynchronous
requests. One blog
post provides a good summary of the points to keep in mind. However,
something very simple that no blog post or Stack Overflow answer seemed to
explicitly cover is that you need to include
:js => true in your test blocks
Finally, note that if your acceptance test involves any interaction with hidden elements
on your page, Capybara may require you to explicitly set
Capybara.ignore_hidden_elements = false (depending on your version).