roll your own test runner for testling [ 2012-01-23 11:23:13 UTC ]

Testling is a browserling product that pkrumins and I put together to make running automated browser tests super easy.

Tests usually look something like this:

var test = require('testling'); test('json parse', function (t) { t.deepEqual( Object.keys({ a : 1, b : 2 }), [ 'a', 'b' ] ); t.end(); });

Then you can run the tests on all the browsers we run using a curl one-liner like this one:

curl -sSNT test.js -u mail@substack.net \ 'http://testling.com/?browsers=chrome/16.0,firefox/9.0,safari/5.1,ie/9.0,ie/7.0'

and when the code blows up (in IE7 in this case because it doesn't have Object.keys), you get a full stack trace!

$ curl -sSNT test.js -u mail@substack.net \ 'http://testling.com/?browsers=chrome/16.0,firefox/9.0,safari/5.1,ie/9.0,ie/7.0' Enter host password for user 'mail@substack.net': Bundling... done chrome/16.0 1/1 100 % ok firefox/9.0 1/1 100 % ok safari/5.1 1/1 100 % ok iexplore/9.0 1/1 100 % ok iexplore/7.0 0/1 0 % ok Error: [object Error] at [anonymous]() in /test.js : line: 4, column: 5 at keys() in /test.js : line: 5, column: 9 at [anonymous]() in /test.js : line: 3, column: 29 at test() in /test.js : line: 3, column: 1 > t.deepEqual( > Object.keys({ a : 1, b : 2 }), > [ 'a', 'b' ] > ); total 4/5 80 % ok

Wow super great! Except perhaps you don't like how the standard test API looks and want something more jasmine-esque and bdd-ish.

Just write a little wrapper like this:

var testling = require('testling'); module.exports = function describe (dname, cb) { if (typeof dname === 'function') { dcb = dname; dname = undefined; } var ix = 0; cb(function it (iname, cb) { var name = (dname ? dname + ' :: ' : '') + (iname || 'test #' + ix++); testling(name, function (t) { var waiting = false; t.wait = function () { waiting = true }; cb(t); if (!waiting) t.end(); }); }); };

And now you can write your tests like so, require()ing the bdd wrapper node.js-style:

var describe = require('./bdd'); describe('arrays', function (it) { it('should map', function (t) { t.deepEqual( [ 97, 98, 99 ].map(function (c) { return String.fromCharCode(c) }), [ 'a', 'b', 'c' ] ); }); it('can do indexOf', function (t) { t.equal([ 'a', 'b', 'c', 'd' ].indexOf('c'), 2); }); }); describe('tests', function (it) { it('can wait', function (t) { t.wait(); var start = Date.now(); setTimeout(function () { var elapsed = Date.now() - start; t.log(elapsed); t.ok(elapsed >= 100); t.end(); }, 100); }); });

Now you have 2 files but you can still use a one-liner to stitch everything together:

$ tar -cf- bdd.js test.js | curl -sSNT- -u mail@substack.net \ 'testling.com/?browsers=chrome/16.0,firefox/9.0,iexplore/9.0' Enter host password for user 'mail@substack.net': Bundling... done chrome/16.0 3/3 100 % ok Log: 101 firefox/9.0 3/3 100 % ok Log: 115 iexplore/9.0 2/3 66 % ok Log: 83 Assertion Error: not ok at [anonymous]() in /test.js : line: 24, column: 13 at ok() in /test.js : line: 24, column: 13 at [anonymous]() in /test.js : line: 21, column: 29 at setTimeout() in /test.js : line: 21, column: 9 at [anonymous]() in /test.js : line: 17, column: 29 at it() in /test.js : line: 17, column: 5 at [anonymous]() in /test.js : line: 16, column: 28 > t.ok(elapsed >= 100); total 8/9 88 % ok

...and strangely enough, IE9 only sleeps for 83 milliseconds when you tell it to sleep for 100! TYPICAL.

Check out the testling documentation, create a browserling account to use with testling, and hack up some crazy browser tests and test runners!