Monday, May 24, 2010

First Pass at Testing My Own Fab.js App

‹prev | My Chain | next›

Stubbornly, I continue tonight trying to get started with testing my fab.js application. I found out last night that there is no easy way to run the fab.js test suite (and a @fabjs tweet this morning confirmed it). Still, I need to be able to test if I am going to seriously use fab.js.

Last night was not a complete waste. I did learn a thing or two about fab.js test strategies. I think that I will start with them tonight. I create my own test.js test suite and pull in the commonjs assert and puts (print):
#!/usr/bin/env node

var assert = require("assert")
, puts = require( "sys" ).puts;
I then manually copy in the contents of fab.js's utils/test.js and pull in a function from my (fab) game to test:
#!/usr/bin/env node

var assert = require("assert")
, puts = require( "sys" ).puts;

// utils/test.js from fab.js

var target_module = require('./lib/player_from_querystring');
test(target_module);
In lib/player_from_querystring.js, I paste the contents of the function that I wrote by hand last week to add a new player to the fab.js game and export it (using the commonjs exports):
function player_from_querystring() {
var out = this;
return function(head) {
if (head.url.search) {
var search = head.url.search.substring(1);
var q = require('querystring').parse(search);
var app = out({ body: {id: q.player, x: q.x || 0, y: q.y || 0} });
if ( app ) app();
}
else {
out();
}
};
}

exports.app = player_from_querystring;
To use that in the test framework, this library also needs to export a list of tests. For now, I just want to test that this is a unary app (which it is by virtue of receiving no arguments:
exports.tests = ( function() {
var app = player_from_querystring( );

return [

function
statusReturnsUnaryApp() {
this( app.length === 1 );
}
];
});
When I run the test framework, however, I get:
cstrom@whitefall:~/repos/my_fab_game$ node ./test.js 
Running 0 tests...
TypeError: Object function () {
var app = player_from_querystring( );

return [

function
statusReturnsUnaryApp() {
this( app.length === 1 );
}
];
} has no method 'forEach'
at test (/home/cstrom/repos/my_fab_game/test.js:13:15)
at Object.<anonymous> (/home/cstrom/repos/my_fab_game/test.js:33:1)
at Module._compile (node.js:639:23)
at node.js:667:20
at fs:52:23
at node.js:748:9
Hrm... I thought the tests being exported returned a list of things to test. What gives?

Ah, I am assigning exports.tests to a function, not the return value of that function. For the lack of an empty parens, my test fail. Adding the parens evaluates that function, returning the list of tests:
exports.tests = ( function() {
var app = player_from_querystring( );

return [
function
statusReturnsUnaryApp() {
this( app.length === 1 );
}
];
})();
With that, I get my first fab.js test to pass:
cstrom@whitefall:~/repos/my_fab_game$ node ./test.js 
Running 1 tests...
statusReturnsUnaryApp: true
Done. 1 passed, 0 failed.
It is not much. But it is a start. Up tomorrow, a retrospective (and B'more on Rails opensource hack night!). After that, perhaps more work with this or moving onto testing some of this with Cucumber.

Day #113

3 comments:

  1. Oh, that's how to run the tests. Thanks for digging into this Chris, your articles and a lot of trial and error have helped me get a better grasp on fabjs. I wish fabjs had a little better documentation, but I also realize the fab team is busy doing a rewrite for v0.5.

    I hope to get some time later on in the week to get vowsjs working fabjs.

    Thanks,
    Graeme

    ReplyDelete
  2. Glad it could help :)

    I'm not sure if fab.js needs more documentation or if I need to understand JS apply/call semantics better. When I'm struggling most, it feels like the latter.

    BTW what is vowsjs? Google doesn't seem to know and now I'm curious :)

    -Chris

    ReplyDelete
  3. Hey Chris -

    I agree that fabjs is pushing my javascript understanding to a higher level. vowsjs is a async BDD testing framework for node:

    http://github.com/cloudhead/vows

    I haven't a chance to play with it yet, trying to limit myself to one new framework at a time ;)

    ~ graeme

    ReplyDelete