Recently, the tests for a frontend web project I’m working on started to become more and more troublesome. Full hangs in the middle of a test run became a frequent issue, destroying my precious coding flow.
I’m using Buster.JS and its server mode, where one or
more browsers are captured as slaves to a server which orchestrates test runs.
buster test on the command line. For anyone following Buster.JS’s
development towards the upcoming 1.0 release, it’s well known that the current
implementation of the server part have stability issues, and it is soon to be
replaced. Thus, as my test suite grew, I wrote off the increasing amount of
test run hangs as the fault of the Buster.JS server.
Of course, this wasn’t the full picture, and as this problem became a lot worse in just a few days, I started investigating other causes. Looking at the console in the browser running the tests, it became evident that some of my tests where doing a lot of failing AJAX requests. Requests that should not have been fired off in the first place, or that should have been caught by a Sinon.JS fake server.
Using Chrome’s console, which gives you the full stack trace leading up to any failed AJAX request, it was easy to identify the code paths that led to the AJAX requests, and subsequently what tests has caused it. In a matter of minutes, I was able to avoid the the AJAX requests either by fixing the implementation or by adding a fake server to the test case, depending on what was appropriate for each case. The effect was instant, and again my test runs became as reliable as they’ve ever been.
So, how can I avoid this from happening again? I don’t want to babysit the browser console for AJAX requests accidentally caused by test runs.
Since none of my tests have a legitimate reason for using real AJAX requests, I
want to fail any test that does an AJAX request that is not caught by a
Sinon.JS fake server. Sinon.JS does its magic by temporarily replacing
window.XMLHttpRequest with a
FakeXMLHttpRequest. Thus, if I got the
XMLHttpRequest object to fail the test, I would have a solution.
One of my first attempts threw an exception when
called, but this didn’t cause the test to fail, since jQuery caught and
ignored the exception. After some fiddling back and forth, I ended up with the
following implementation, which simply asks Buster.JS to fail the current
test. This could easily be modified to work with any other test library.
The code needs to run in the browser before the tests are executed. In the Buster.JS life cycle, it fits perfectly as a “test helper”. Test helpers are executed after your libraries and source code, but before your test code.
Just put the above code in a file named e.g.
testHelpers/fail-on-uncaptured-ajax-use.js, and then add it to the
testHelpers section of your
buster.js config file:
Then, when you run a test which creates uncaptured AJAX requests, your test will fail hard: