matthew ephraim

Screwing Around With Screw.Unit

I just started using the delightfully named Screw.Unit for JavaScript testing, and I have to say that, so far, I’m pretty pleased with it. Screw.Unit is a JavaScript testing framework that allows you to easily create and run unit tests for your JavaScript code. For example, here is a really simple hello world type test written with Screw.Unit:

JavaScript/Screw.Unit
describe("A simple hello world test", function()
{
    it("is a test for truth example", function()
    {
        expect(true).to(equal, true);
    };
};

If I were to run the test on a page that had the framework loaded in, I’d get a nice pretty rundown of my tests, showing that the hello world test had indeed passed (true does, in fact, equal true).

One thing that I immediately wondered about was how the keywords in the framework worked. At first, I assumed they were global variables and was a little put off by that idea. Would functionality like “describe”, “expect” and “it” interfere with other code that happened to use those same function names or variables? Fortunately, I was surprised to find this code in the framework:

JavaScript/Screw.Unit
var contents = fn.toString().match(/^[^\{]*{((.*\n*)*)}/m)[1];
var fn = new Function("matchers", "specifications",
  "with (specifications) { with (matchers) { " + contents + " } }"
);

fn.call(this, Screw.Matchers, Screw.Specifications);

Located in the initialization portion of Screw.Unit, this cryptic looking piece of code is actually doing something very clever. It’s using the Function.toString() method to extract the content of the function wrapper around all of your tests. It’s then taking the contents of that function and creating a new function that is using the “with” keyword to execute your code in the context of the framework’s keywords and functions.

In other words, it’s taking your tests and tricking JavaScript into thinking that your test functions have access to the properties and methods stored in Screw.Matchers and Screw.Specifications. This gives you access to the framework functionality without leaking any variables into the global namespace.

That sort of cleverness gives me hope that JavaScript has a bright future ahead.