Once you’ve used rspec, getting back to the JUnit style of testing is as attractive as an overdue visit to the dentist. Not a lot of fun. So when it became time to test some Javascript code, I started looking for an equivalent to rspec like an espresso addict for a La Marzocco machine. And found a pearl: js-spec.

Right now it’s beta code but it worked for most of the things I’ve tried. You might have to look at the source code a couple times to see how it works as the documentation isn’t really extensive yet. But it’s pretty self-explanatory anyway. Check this:

describe(“js-spec”, function() { with(this) {

it(“should pass when doing simple comparisons”, function() {
(1).should( equal(1) );
(1).should( be_less_than(2) );
(1).should( be_greater_than(0) );
(1).should_not( equal(2) );
(1).should_not( be(1) ); // ‘be’ checks if it’s the same object
});

it(“should pass when checking if a value is within a delta of another”, function() {
// first argument is the target, second one the maximum allowed difference between both numbers
(1.0).should( be_close(1.05, 0.1) );
(1.0).should_not( be_close(1.5, 0.1) );
});

it(“should pass when checking if a method changes an object”, function() {
[1, 2, 3, 4].should_not( change(“length”).in_response_to(“size”) );
// the next example would also pass if you changed ‘to(3)’ to ‘from(4)’ or ‘by(-1)’
[1, 2, 3, 4].should( change(“length”).to(3).in_response_to(“pop”) );
// it also works for functions, and you can even pass parameters to them:
[1, 2, 3, 4].should( change(“first”).to(0).in_response_to(“unshift”, 0) );
});

it(“should pass when checking how many elements has an enumerable”, function() {
$(“some_container”).should( have(1, “childElements”) );
[1, 2, 3, 4].should( have(2, “slice”, 0, 2) ); // equivalent to [1, 2, 3, 4].slice(0, 2).length.should( equal(2) )
$(“some_container”).down(“span”).should_not( have_at_least(1, “childElements”) );

});

it(“should pass when asking if an enumerable includes some elements”, function() {
[1, 2, 3, 4].should( include(1, 2) );
[1, 2, 3, 4].should_not( include(0) );
})

it(“should match strings to regexps”, function() {
“to be or not to be”.should_not( match(/^2b|[^b]{2}$/) );
“Something”.should( match(/^[Ss]/) );
});
}});

Refreshing, isn’t it? And there’s much more. The culprit right now is to test for nullity as you can’t add methods on null in Javascript as you can in Ruby. But I’m thinking of a solution that I could contribute.

The main problem, at least for me, was that I wanted to run my tests server-side in Rhino, not in a browser. And js-spec uses Prototype which more or less assumes the presence of a browser. Annoying. But that’s without counting the brilliant work of John Resig and his little library that fakes the browser environment. Which saved me.

Now my test script looks like this:

load(“3rdparty/browser-env.js”);
window.location = “test/index.html”;
load(“3rdparty/prototype.js”);
load(“3rdparty/jsspec.js”);

load(“src/my_script_to_test.js”);

with(Spec) {
// Tests go here
}

Specs.report = “ConsoleReport”;
Specs.run();

You have to set the window location to an existing HTML document for the environment to be properly initialized. What the document contains doesn’t really matter as long as it has a body, I just use a dummy one.

And voila! you have a robust server side testing environment for your Javascript programs, forget the browser and Firebug.