Browserless AJAX Testing with Rhino and Envjs, Part 1.
Updates - 5/27/2011
Since this original post, there has been a lot of good feedback surrounding getting an Envjs + QUnit + Rhino setup going, so please read the comments at the bottom of this post. Here are the summarized points:
- QUnit: Newer versions of QUnit have issues with Envjs, adding a
<pre/>to output that Envjs can’t handle. A comment from “Ryan” (not me – I’m “Ryan Roemer” below) also points out the QUnit has changed the function signature of the logging callbacks and links to an improved “setup.js” file. I have inserted links to a known working version of QUnit.
- jQuery 1.5: jQuery 1.5+ also has issues with Envjs due to calls to a couple of methods not currently available in either Envjs 1.2 or 1.3. There is a patch on GitHub for the issue for Envjs 1.3. I have backported the patch (and some other fixes) to a forked version of Envjs 1.2 on my GitHub account.
On the frontend, it’s a different story. Our previous test suite relied entirely on a browser and a running development server loaded with data in a known state. Our unit tests were written against QUnit, and for the most part worked fine for the code they did exercise. But, even where our frontend tests would catch newly introduced bugs, all too often the tests just weren’t run, and we would actually discover the bug several commit cycles later.
While we clearly need to integrate a fully automated infrastructure around browser-based tests (using great tools like Selenium or Windmill), my thoughts turned to the idea that the heavyweight nature of full end-to-end AJAX testing was getting in the way of us writing and running frontend tests. More specifically, the difficulties come down to two fundamental problems – our tests on the frontend are: (1) not easy to write and run, and (2) are not integrated into an automated, “one-touch” running scheme.
Thus, the second step necessary for running QUnit tests is a simulation of the browser environment (e.g., window, console, etc.), just without the browser. This is a harder problem.
So years later, looking back into the issue, I was pleased to revisit Resig’s proof-of-concept browser simulation environment and find that it had evolved into a full open source project – Envjs – which provides an amazingly powerful browser-like environment, capable of DOM manipulation, AJAX interaction, cookie setting, etc.
So, let’s get started.
Rhino and Envjs Installation
In terms of extra tools / libraries, all we need is Rhino and Envjs:
Rhino is available from the Mozilla FTP site. I ended up going with rhino1_7R2 – the Envjs web site notes that it is best to go with a recent Rhino release. The package can be installed anywhere, but we are going to need to know the path to the file “js.jar” in the package to pass as a class path argument to Java.
After installing, let’s check that Rhino actually works:
Example Libraries and Test Code
Ignoring how I actually installed and placed files, for the rest of this discussion, let’s assume we have a simplified world view in a single working directory, where we’ll place all our third party, test and library code. None of these files really need (or should) be in the same directory, but it is easier to describe things without multiple directory traversal.
Here is the third party code:
env.rhino.1.2.js: The Envjs file we downloaded. If you are using jQuery 1.5+, you may want this patched Envjs instead.
qunit.css: QUnit styles. (Link to known working version).
qunit.js: QUnit code. (Link to known working version).
We are going to create two more files in a subsequent section.
setup.js: Hook Envjs to QUnit.
run-tests.js: Include our setup script and actually invoke the tests at on our test HTML page.
And, here is some library and test code files:
test.html: Basic QUnit HTML page (see QUnit documentation) with script links to “my-lib.js” and “my-tests.js”.
Once we’ve got all of these custom and third party files, we can just open test.html in a browser, and the QUnit tests should all run, pass and look something like:
[![QUnit results][img_qunit_th]][img_qunit] [img_qunit_th]: http://loose-bits.com/media/img/2011/02/08/qunit_thumb.png [img_qunit]: http://loose-bits.com/media/img/2011/02/08/qunit.png
Configuring Envjs and QUnit
We need to hook QUnit into Envjs, so we can display output to stdout (using
console.log()). Fortunately, QUnit explicitly provides a lot of hooks to do
everything we want, which I’ve implemented in a file named “setup.js”, placed
I mostly followed the excellent guide from the Envjs folks, and here’s the gist of my configuration for “setup.js”:
Test it Out!
Now that we have Rhino, Envjs and QUnit all hooked together, it’s time to actually run some QUnit tests. Assuming your file / directory setup matches the above contrived example, we should be able to run the tests by invoking Rhino with our test runner script:
Awesome. We have QUnit testing goodness for our library, running within Rhino, and log / results output to the console, all through a single bash command. We can add and include more libraries and test suites to test.html, and they automatically get picked up by the test suite.
Next Time – Browserless AJAX, Playing with the DOM and More!