Javascript unit tests with JS Test Driver

The general idea for JS Test Driver is that it allows you to run javascript unit tests. While this is nothing new, there are some interesting bits. JSTD provides XML output of tests running, which can be used for CI integration and test coverage. It can also run your tests across multiple browsers.

JS Test Driver Installation

JSTD's only dependencies are java and a browser, which makes it very easy to get it setup. I'm assuming you are on an Ubuntu machine, if you aren't, you're on your own.

sudo apt-get install openjdk-6-jre firefox # install java & firefox

Now that those are installed, you can download the jar. This link is likely out of date, but you can find a more up to date version on the download page.

java -jar JsTestDriver-1.2.2.jar --port 4224 --browser `which firefox` &

This should open up a firefox session and attach it to the JSTD service. You'll know this is working if you see a green bar at the top of the firefox window. From here, JSTD is waiting on tests to run.

Before we run tests, we'll need to write out a quick config file for the test runner. My config.cfg file looks something like this:

    server: http://localhost:4224

    load:
      - media/js/jquery.min.js
      - tests/*.js

This tells our runner where it can find the waiting JSTD server and which javascript files to load. It should load all of your dependencies, such as jQuery, as well as all the tests you'd like to run.

The command for running all of the included tests is:

    java -jar JsTestDriver-1.2.2.jar --config config.cfg --tests all --reset

The "–tests all" flag allows you to specify which tests you want to run. In our case, we likely want to run them all. The "–reset" flag resets the browser to a known good state before beginning.

Running a Headless browser

While all of the previous information holds true for running JSTD in headless mode (for a server, possibly), it assumes you have a desktop session to run a browser in. If this isn't the case, for instance on your CI machine, you can get one setup fairly easily. You must download the xvfb (X Virtual Framebuffer) package. This basically provides a virtual X session which you can run X-only programs, like firefox, in. Once its installed, you can invoke it with Xvfb :0 & which runs it on display :0. To run firefox in this framebuffer, try "DISPLAY=":0"-" firefox &=. This should launch firefox in the hidden framebuffer. You might be wondering how you can validate what's happening in this buffer; The answer is with a screenshot. Install the meta-package x11-apps, which should provide you with access to the xwd command, which is used to take screenshots. You can take a screenshot of the desktop with:

    xwd -root -display :0 > desktop.img

This file is able to be read by GIMP. Should you not have it, wikipedia suggests the command xwd | xwdtopnm | pnmtopng > Screenshot.png as a way to get it to png output, but I haven't validated it.

Writing Tests

There are two methods for writing tests. One involves the prototype attribute on your TestCase, the other involves passing an object to your TestCase constructor. In each, you provide a function, which takes no arguments. This function is called to run the functions and asserts for the target of the tests. In each function, you can provide a comment reminiscent of Python's docstrings which will alter the browser's DOM. This seems roughly analogous to having a particular setUp function or fixture loading which prepares the state of your suite, but is on a per-test basis. Its also worth noting that JSTD also provides setUp and tearDown methods as you might expect.

The examples from the TestCase documentation do a great job of outlining the difference between the prototype and inline test definition process.

    // Prototype
    MyTestCase = TestCase("MyTestCase");
    MyTestCase.prototype.testA = function(){ };
    MyTestCase.prototype.testB = function(){ };

    // Inline
    TestCase("MyTestCase", {
        testA:function(){ },
        testB:function(){ }
    });

If you want to create HTML for use in your test, it would look something like:

    MyTestCase.prototype.testA = function () {
    /* :DOC += <div>
        <p>This will be appended to the body</p>
      </div>
    */
    }

JSTD resets these DOM additions after each test. The HTML Docs suggest that there is a way to provide named snippets such that you can refer to the HTML blocks as javascript attributes, but I don't particularly have a need for that. View the documentation for more details. It is worth noting that the HTML you append should be rooted by a single node, not multiple nodes.

Hooking it into Continuous Integration

Once the above installation has taken place and you have some tests written, now its time to hook everything into a CI server. This will be based on Hudson, though I expect most others have a similar process.

The easiest solution here is to just run the test runner on a successful build. It will properly output the results and return the correct status code on failures. This is just as simple as adding the above test runner command as a build step.

To get more out of the test runner, you can have it output test results to an xml file. The flag for that is --testOutput /path/to/test/dir where the path to the test directory is where it will dump its XML file. The format of the files it dumps are TEST-Browser-pidOS.TestCaseName.xml. You can pass this to Hudson's "Publish JUnit test result report" option as: **/TEST-Firefox_*_Linux.*.xml,**/nosetests.xml where the **/nosetests.xml portion represents what it would look like were it combined with another XML test report.

The JSTD wiki also suggests that you can get code coverage, but I also haven't tested whether this will integrate with Hudson's Cobertura plugin yet.