Client-Side Testing of Servers… in JavaScript
I have a very simple desire. I want to do black box testing of my server-side code. Which means I need to fire a bunch of HTTP requests at the server and pay attention to both the data sent back and the HTTP response codes because I’m aiming for a RESTful API. Since JavaScript is rapidly becoming my favourite language, I’d prefer to do it in JavaScript. And, I’d prefer to use XMLHTTPRequests because they are comfortably familiar. Oh, and I want to run the tests from the command line (and scripts and such) rather than in a browser.
First contender: SpiderMonkey, the grand-daddy of all JavaScript engines. SpiderMonkey is the JavaScript engine in Mozilla and its descendants (and is itself the latest generation of the original Netscape JavaScript engine). The command line version is small, fast, builds on Mac OS X out of the box, and doesn’t have any of the browser-related classes. I could write a libcurl-based XMLHTTPRequest implementation and get SpiderMonkey to export my C extension into the JavaScript environment. But I want to write tests, not extensions. SpiderMonkey is awesome as an interactive JavaScript environment, though, because it’s faster and far smaller than Rhino.
Speaking of Rhino, it’s the second contender. Rhino is a Java-based JavaScript interpreter. It was created at Netscape when they tried building the entire browser in Java. They scrapped the product, but Rhino survived. It’s the Interpreter of choice for server-side JavaScript engines. But it doesn’t have the browser classes either. Again, I could write my own XMLHTTPResource, but I don’t want to. As an interactive environment Rhino is a bit slower than SpiderMonkey and a fair bit larger (especially when you factor Java in). Still, in interactive mode you’d be hard-pressed to tell the difference.
There is one last option from the Mozilla folks. And that option is Mozilla, or, more precisely, a part of the browser: xpcshell. The big Mozilla browser (and it’s rechristened existence as SeaMonkey) has a whole lot of components. One of those components is a command line JavaScript interpreter, xpcshell. Basically, it’s SpiderMonkey with a huge web browser grafted onto it. And that’s the key, the huge web browser brings with it all the web browser infrastructure, including XMLHTTPRequest.
So, I have found my tool hidden deep within the bowels of SeaMonkey. SeaMonkey.app/Contents/MacOS/xpcshell to be exact. (Windows and Linux users can rest assured that XPCShell is bundled with SeaMonkey, but you’ll have to go on your own personal safari to find it.)
And now, the thorn in the rose. XPCShell does indeed give you access to XMLHTTPRequest, but not as the friendly global object we all know and love. You have to bring it into the JavaScript environment yourself via the XPCom bindings. Luckily, that turns out to be really simple. All we have to do is define our own XMLHTTPRequest constructor that returns an XMLHTTPRequest generated via the XPCOM interface. (Which sounds way more complicated than it is.)
if (XMLHTTPRequest === undefined) {
var XMLHTTPRequest = function () {
var class = "@mozilla.org/xmlextras/xmlhttprequest;1";
var service = Components.interfaces.nsIXMLHttpRequest;
return Components.classes[class].getService(service);
}
}
I added the class and service variables to keep the line length down since long lines of code tend to look like crap in my blog layout. So feel free to optimize them out.
And that’s it, I have a command line JavaScript interpreter that gives me XMLHTTRequest. If you’ll excuse me, I have some tests to write.
