I think I have a handle on testing simple upstream fab.js apps. Tonight I will see if that ability transfers to testing binary (aka middleware) apps.
I have a middleware app that translates a new player response into a comet response:
( /^\/comet_view/ )The actual app looks like a normal, albeit large fab.js binary app:
( init_comet )
( player_from_querystring )
function init_comet (app) {Actually, wow. There is a lot going on there. I obviously didn't TDD that app. Let's see if I can drive a series of smaller apps. I break the
return function () {
var out = this;
return app.call( function listener(obj) {
if (obj && obj.body) {
var downstream = out({ headers: { "content-type": "text/html" },
body: "<html><body>\n" })
// Send a bunch of output to initialize the comet session in some browsers
var downstream = out({ headers: { "content-type": "text/html" },
body: "<html><body>\n" })
({body: "<script type=\"text/javascript\">\"123456789 123456789 123456789 123456789 123456789 12345\";</script>\n"})
// ... many more of these lines to push pass Chrome's buffer
// Tell all other players about the new one
for (var id in players) {
downstream = downstream({body: comet_walk_player(JSON.stringify(players[id].status))});
}
// Add the new player to the player list
var new_id = obj.body.id;
puts("adding: " + new_id);
players[new_id] = {status: obj.body, listener: out};
// Establish an inactivity watch for the user
idle_watch(new_id);
// tell the user the game is aware of it
broadcast(comet_walk_player(JSON.stringify(obj.body)));
}
return listener;
});
};
}
init_comet
app out of my main game.js
application and into lib/init_comet
. Since this is a binary app, I start with a skeleton binary app along with the initial comet reply:var puts = require( "sys" ).puts;Next, I write my test. For now, I want to see if I can test that the middleware returns an HTML document back downstream:
function init_comet (app) {
return function () {
var out = this;
return app.call( function listener(obj) {
if (obj && obj.body) {
var downstream = out({ headers: { "content-type": "text/html" },
body: "<html><body>\n" })
// Send a bunch of output to initialize the comet session in some browsers
var downstream = out({ headers: { "content-type": "text/html" },
body: "<html><body>\n" })
({body: "<script type=\"text/javascript\">\"123456789 123456789 123456789 123456789 123456789 12345\";</script>\n"})
// ... many more of these lines to push pass Chrome's buffer
}
});
}
}
exports.tests = ( function() {I create a dummy upstream app. For now, it only needs to reply with a body. I then get the result of calling my
var upstream = function() { this({body:{id:42}}); },
downstream = init_comet (upstream);
return [
function
bodyRespondsWithStartHtml() {
var out = this;
downstream.call(function(obj) {
out(obj.body == "<html><body>\n");
});
}
];
})();
init_comet
app with that upstream app. If I have done this right, init_comet
will call the supplied callback. I then send the result of my test back to the test harness with out
. Unfortunately, when I run this, I get:cstrom@whitefall:~/repos/my_fab_game$ node test.jsAh. Not too bad. The test passes, but that backtrace... Ew.
Running 1 tests...
bodyRespondsWithStartHtml: true
TypeError: undefined is not a function
at CALL_NON_FUNCTION (native)
at /home/cstrom/repos/my_fab_game/lib/init_comet.js:50:21
at listener (/home/cstrom/repos/my_fab_game/lib/init_comet.js:9:26)
at Function.<anonymous> (/home/cstrom/repos/my_fab_game/lib/init_comet.js:42:31)
at Function.<anonymous> (/home/cstrom/repos/my_fab_game/lib/init_comet.js:7:16)
at Function.bodyRespondsWithStartHtml (/home/cstrom/repos/my_fab_game/lib/init_comet.js:49:13)
at /home/cstrom/repos/my_fab_game/test.js:14:10
at Array.forEach (native)
at test (/home/cstrom/repos/my_fab_game/test.js:13:15)
at Object.<anonymous> (/home/cstrom/repos/my_fab_game/test.js:36:1)
The
init_comet
app calls the downstream app with "<html><body>\n"
and then calls the result of that with some of that comet buffer breaker data. I should simply need to return a function to be called:exports.tests = ( function() {Again, however, I get the same error:
var upstream = function() { this({body:{id:42}}); },
downstream = init_comet (upstream);
return [
function
bodyRespondsWithStartHtml() {
var out = this;
downstream.call(function(obj) {
out(obj.body == "<html><body>\n");
return function() {};
});
}
];
})();
cstrom@whitefall:~/repos/my_fab_game$ node test.jsI finally get this passing by returning the same listener:
Running 1 tests...
bodyRespondsWithStartHtml: true
Done. 1 passed, 0 failed.
TypeError: undefined is not a function
at CALL_NON_FUNCTION (native)
at listener (/home/cstrom/repos/my_fab_game/lib/init_comet.js:12:125)
at Function.<anonymous> (/home/cstrom/repos/my_fab_game/lib/init_comet.js:30:31)
at Function.<anonymous> (/home/cstrom/repos/my_fab_game/lib/init_comet.js:7:16)
at Function.bodyRespondsWithStartHtml (/home/cstrom/repos/my_fab_game/lib/init_comet.js:39:13)
at /home/cstrom/repos/my_fab_game/test.js:14:10
at Array.forEach (native)
at test (/home/cstrom/repos/my_fab_game/test.js:13:15)
at Object.<anonymous> (/home/cstrom/repos/my_fab_game/test.js:36:1)
at Module._compile (node.js:639:23)
functionI must confess that I do not understand why returning the listener as opposed to an anonymous function worked. Something to investigate tomorrow.
bodyRespondsWithStartHtml() {
var out = this,
already_tested = false;
downstream.call(function listener(obj) {
if (!already_tested) out(obj.body === "<html><body>\n");
already_tested = true;
return listener;
});
}
Day #117
No comments:
Post a Comment