Asynchronous JavaScript Testing in Jasmine, Mocha, and Vows

Posted on by in Development, Process

The rise in popularity of JavaScript, especially on the server-side, has introduced more and more developers to asynchronous programming. Asynchronous, event-driven programming also requires a change in testing. In this post, we’ll look at how three popular JavaScript testing frameworks support testing asynchronous code.

Jasmine

The first framework we’ll look at is Jasmine. Jasmine is a popular testing framework built to test client-side JavaScript. jasmine-node is a fork of Jasmine for testing server-side JavaScript in node.js. Both offer support for testing asynchronous code. Let’s first look at Jasmine’s support for asynchronous testing, then we’ll refactor to jasmine-node’s cleaner, simpler syntax.

The following example uses Jasmine’s asynchronous testing support to test the readFile function in the node.js file system module.

In Jasmine, asynchronous code has to be executed in a function passed to the runs function. In our example, this is where we call the asynchronous readFile function. Our readFile callback checks for errors, saves the contents of the file, and then sets a “done” flag.

After passing our asynchronous code to runs, we need to tell Jasmine to wait until our asynchronous code has executed. Jasmine’s waitsFor function expects a function that returns a boolean value indicating the status of your asynchronous code. In our example, we return the “done” flag that we set in our asynchronous callback.

Expectations of asynchronous code must also be declared in a function passed to runs. Above, we expect some file content to have been read by node.js.

jasmine-node

jasmine-node integrates Jasmine with node.js. It adds simpler, more elegant asynchronous testing support to Jasmine. The following is a rewrite in jasmine-node of our previous test.

In jasmine-node, a “done” function is passed to any setup, teardown, or example functions that declare a parameter. jasmine-node will then wait until the passed “done” function is called before executing the rest of the test. If the callback isn’t called after 5 seconds (the default timeout) the test will fail.

Mocha

mocha is another popular JavaScript testing framework. Its asynchronous testing support is identical to jasmine-node‘s.

The following is an example using mocha to test a simple express app (for simplicity, the express app is defined in the same file).

This example is similar to our jasmine-node example. In it, we declare a single parameter anonymous function for our beforeEach hook. In our asynchronous callback we invoke the “done” function that was passed to our beforeEach hook. This tells mocha, which is waiting for the “done” function to be invoked, to continue executing the rest of the test.

Vows

Vows is yet another JavaScript testing framework. Vows claims to have been developed from the start to test asynchronous code.

The following is a vows test for connecting to a socket.io server, registering an asynchronous message listener, and verifying the listener is called.

In vows, a topic is a test fixture. A topic is passed to each vow (a function that runs assertions on a topic). For asychronous tests, vows provides a callback function. This callback function should be passed to your asynchronous code. When this callback is called, it will pass on its arguments to each vow. The above test includes a single vow that expects a welcome message from the socket server, after connecting to it.

One gotcha with vows is that if you use the callback function in your topic function, then your topic function must not return anything. Since CoffeeScript functions implicitly return their last expression, we had to explicitly return undefined. Vows offers an alternative syntax for asynchronous topics using promises. Here’s an example test using this syntax.

In this test, we define a topic that returns a promise. This promise emits a “success” event in the asynchronous Google.search callback. The HTTP response object passed to the callback is passed along in the “success” event, which is in turn, passed along to the single vow.

Get Some Coverage

All of these testing frameworks offer good support for writing clear tests for asynchronous code. Personally, I prefer the asynchronous syntax in jasmine-node and mocha. It’s clean and easy to understand. Vows is impressive, but I’m not a fan of its novel syntax and terminology (I just can’t get used to calling a test a “vow”). As a fan of CoffeeScript, I’m also annoyed by vows’ return value requirement for asynchronous topics. I suggest you give each framework a try. The important thing is to get some coverage for all your convoluted JavaScript code.