Motivation
For my thesis, I’m writing a little application using ExtJS. The app itself is nothing special, but the thesis’ focus is on testing web applications – and in the awesome, agile and extreme programming world of 2011, this really means “testing JavaScript using the same proven methods and the same rigour as with testing our server side application”. However, this is not as easy as one might hope.
A quick overview of the java script testing frameworks
For once, there’s a shitload of unit test runners for JavaScript to choose from: At least every major JS framework has its own unit testing tools, plus there’s quite a few generic ones. And the reason everyone is writing their own is because they all suck. It’s pretty much like writing your own web framework a couple of years ago. All of these frameworks can be categorized into two categories by the approach to the problem they’ve chosen:
You can implement your test runner in JavaScript and make it run in a browser. So the developer will setup some HTML page, include your test runner, the code under test and the unit test files and the test runner will execute the tests and manipulate the DOM to show the results. An example of this approach can be seen on the JsUnit demo page. This is can be used with every browser you are targeting and can display fancy results right in your browser. There’s one tiny little problem though: This can’t be (easily) integrated into a continuous integration system because the in-browser-test-runner just can’t write the results to an XML file. Also, running your tests from the shell just looks so much cooler
The alternative is using a javascript engine outside of the browser, like RhinoUnit does by leveraging Rhino, which emulates Mozillas JS engine. The problem with this is that you just can’t emulate every browser’s JavaScript engine in a tool like this and emulation is never perfect, so you might not find bugs that are caused by different implementations of JavaScript. So this is not a good solution either. Also, Rhino is reeeeeheeeeaheeeeeeally slow.
Someone at Google was clever enough to come up with a really simple and obvious better approach and developed JsTestDriver: It’s combining the two failing approaches by using a simple client/server setup to distribute tests to browsers and gather the results: Browsers are “captured” by visiting a page on the mini http server started by JSTD. That server can then send javascript code and test cases to the browsers, where they are executed and the results sent back. This not only allows to write the results to an XML file to be picked up by Jenkins or another CI system, it’s also really fast (despite being written in Java). And you can use it with every browser you want to support. Writing a unit test in JSTD is really simple (I won’t go into how to actually run this here, it’s pretty easy and covered on the Getting Startedpage):
TestCase("RomanNumbersTest", {
"test 1 in roman": function () {
assertEquals("I", to_roman(1));
},
"test 2 in roman": function () {
assertEquals("II", to_roman(2));
}
});
Also, while it includes all your usual xUnit style assertions, it is also compatible with some of the other frameworks such as Jasmine or QUnit. So,JSTD is the way to go. Now, let’s test our fancy Ext application, should be equally easy, right?
ExtJS 4 and dynamic class loading
Now, because Version 4 of the Ext JS framework is already on Beta3 and the final version should be out in a few weeks, I decided to take the risk and start using it for my thesis. The architecture of Ext is really impressive. They have a very clean API and an awesome documentation which makes this a joy to work with. One of the key features of Ext 4 is “dynamic class loading”: You can just instantiate objects using their name and it will load the appropriate JavaScript file if it’s not available already. For example, when you have a file /myapp/controller/FooController.js, which defines a class FooController, then you can access this in ExtJs using “myapp.controller.FooController” just as you would in Python or Java and the framework will know where to load it from (it’s plain old convention over configuration really). They are also working on a command line tool which generates a minified, single-file version of all your files for deployment, but unfortunately that’s not available yet. So, all you need to do is include the ext-all.js and your main application.js files in your html page and you’re done.
Testing ExtJs 4 applications using JS-Test-Driver
Now, with JSTD this causes problems: I don’t know how exactly JSTD sends the javascript files to the test browsers and executes them, but I had to put in a lot of work to get it running without causing incomprehensible errors. There’s two key factors I identified: First, your JS files will be served under the “/test/” base directory of the JSTD web server which is probably not the same behaviour as your development and production environments. For this reason, you have to adjust the “appFolder” setting of the Application configuration object, which is as simple as using sed to modify the file (see below for my script).
The other thing is that it was not enough just to include ext-all.js and Application.js – the dynamic loading does something (I can see the GET requests), but it just won’t do the trick for some reason I could not figure out. May be a bug in Ext, may be something JSTD does that browsers don’t, may be me being stupid. So, this is a jstd.conf for a standard Ext JS 4 MVC directory layout looks something like this:
load: - js/extjs/ext-all-debug.js - js/timetable/Application.js - js/timetable/controller/*.js - js/timetable/model/*.js - js/timetable/store/*.js - js/timetable/view/*.js test: - unit/*.js - unit/controller/*.js - unit/model/*.js - unit/store/*.js - unit/view/*.js
So with all of this sorted out, you can now test any ExtJS class you want to, for example you could unit test a validator on a model like this:
"test name must be longer than 4 characters": function () {
var e = Ext.ModelManager.create({
name:'abc'
}, 'myApp.model.myModel');
assertFalse(e.isValid());
},
Wrapping up: CI and Conclusion
On the JSTD wiki, I found a nice script to run the JSTD server, open the capute page in a browser and start the tests to be used in a continuous integration system using a virtual framebuffer, which I used for my own project. I added some stuff to run all of this on my development computer, because to really get the integration of JSTD, ExtJS and my directory structure to work I had to navigate around a few other issues. It really is a dirty hack involving creating a temporary directory, copying all my files over and using sed to make the needed change to my Application.js, but for no, this satisfies my needs. You can get a copy of my script in case you’re having similar trouble. Also, feel free to contact me if I can help out or you just want to chat about test-driven web development, which will be all I’m doing for the next three months anyway.
Thanks for this article. I’m trying to find a decent JavaScript unit test framework and you gave a nice overview here.
Have you had a chance to try Ext 4, now that it is out of beta? Any differences in the required setup?
Hi,
there were only subtle changes from the betas to final so the setup should still work. One thing I had to do after I wrote more tests was to replace the wildcards in jstestdriver.conf with a complete list of files in the correct load order. E.g. if you have two classes B and C extending class A, you have to make sure A is loaded first and the error message won’t give you the slightest idea where the error was. Apart from that, I’m still having a hard time testing real-world views and controllers. I’ll try to post some detailed follow-up articles with examples over the next weeks. Feel free to contact me if you’re running into trouble, would love to talk about ext4 testing stuff