Before Christmas, I begun investigating JavaScript unit testing frameworks in an effort to increase the test coverage for my web projects. I’ve had a busy month since then, moving and changing jobs, but now I’m back on track and ready to try out another framework. So today, I’ll be looking at JSSpec, which is a Behavior Driven Development framework.
Code by Example
In JSSpec, specifications are referred to as containing one or more “examples” (tests) which “describe” (fixtures) the behavior. This wording of the specifications helps enforce the idea that a test should not only verify the behavior of a given piece of code, but also “serve as documentation and at the same time reveal the intent of the code”.
Rewriting the InlineEditor Test Suite with JSSpec
When investigating YUITest, I wrote a simple InlineEditor component complete with a set of tests as an example. Those tests looked like this one:
var testCase0 = new YAHOO.tool.TestCase(
{
name: "When entering editing mode",
setUp: function()
{
var span = $("<span id='span'>test</span>"); // create the span to edit
span.appendTo($('#container')); // append it to the test container
this.editor = new InlineEditor(span);
YAHOO.util.UserAction.click(span[0]); // click to begin editing
},
test_span_is_turned_into_input: function()
{
var input = $('#span'); // find the element in the document
// element should now be replaced with an input element
YAHOO.util.Assert.isInstanceOf(HTMLInputElement, input[0]);
},
test_input_has_same_text_as_span: function()
{
var input = $('#span');
YAHOO.util.Assert.areEqual('test', input.val());
},
tearDown: function()
{
$('#container').empty(); // clear the container
delete this.editor;
}
});
Migrating the tests to JSSpec wasn't difficult – in part thanks to the fact that I had already written my tests using YUITest with a bdd-style approach. The test above, for example, now looks like this:
describe('When entering editing mode',
{
before_each: function()
{
container = $("<div/>");
container.appendTo($("body"));
original_text = 'test';
var span = $("<span id='span'></span>"); // create the span to edit
span.text(original_text);
span.appendTo(container); // append it to the test container
var editor = new InlineEditor(span);
editor.beginEdit();
},
after_each: function()
{
container.remove();
},
'span should turn into editor': function()
{
var inputs = $('input').filter('#span'); // find the element in the document
value_of(inputs).should_have(1, "length");
},
'editor should have text of span': function()
{
var input = $('#span');
value_of(input.val()).should_be(original_text);
}
});
So what has changed? Where we had setUp and tearDown methods in YUITest, we now have before_each and after_each methods in JSSpec. The test methods are declared with string names in JSSpec, which means I can now use spaces and write more natural names for them (plus no need to prefix their names with ‘test’). The assertion syntax is a bit different too – JSSpec uses a fluent API that again reads a bit more easily.
All in all, I think I prefer the syntax of JSSpec. It also has a very nice test runner UI:
The API is fairly easy to grasp too, and though the documentation is fairly concise (especially compared to YUITest) it covers everything you need to know. All in all, JSSpec is one of those frameworks that you pick up and hit the ground running with, which is awesome.
A Minimalistic Framework
Feature-wise however, YUITest wins hands down. Where JSSpec is strictly offering a testing framework with the minimal set of features you need, YUITest has a much larger bag of tricks. For instance, JSSpec has no helpers for testing asynchronous code (Ajax stuff) or interacting with UI elements (faking mouse/keyboard events etc) – you’ll have to either roll your own or rely on something like jQuery for that stuff. Assertions are a bit sparse too – I really miss things like YUITests data type assertion (isArray/isString/… and the more generic isTypeOf/isInstanceOf).
Continous Integration
Unlike YUITest, JSSpec has no built-in extension API for reporting test results. However, the test runner produces a clean html output which won’t be too hard to parse if you were to for instance fire it up from a custom build task in TFS:
Download Example Code
You can download the complete InlineEditor example with a suite of JSSpec tests here.