From 40e08eee5d3f14fa9fcbdc7968908015f6190479 Mon Sep 17 00:00:00 2001 From: TJ Holowaychuk Date: Wed, 18 Jan 2012 16:40:58 -0800 Subject: [PATCH] started Runner test coverage need more but its a start. --- lib/runner.js | 54 ++++++++++++++----------- package.json | 2 +- test/runner.js | 105 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 23 deletions(-) create mode 100644 test/runner.js diff --git a/lib/runner.js b/lib/runner.js index 6132757ddc..9bb25be377 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -75,6 +75,7 @@ Runner.prototype.grep = function(re){ */ Runner.prototype.globals = function(arr){ + if (0 == arguments.length) return this._globals; debug('globals %j', arr); utils.forEach(arr, function(arr){ this._globals.push(arr); @@ -132,7 +133,6 @@ Runner.prototype.fail = function(test, err){ */ Runner.prototype.failHook = function(hook, err){ - ++this.failures; this.fail(hook, err); this.emit('end'); }; @@ -368,6 +368,32 @@ Runner.prototype.runSuite = function(suite, fn){ }); }; +/** + * Handle uncaught exceptions. + * + * @param {Error} err + * @api private + */ + +Runner.prototype.uncaught = function(err){ + debug('uncaught exception'); + var runnable = this.currentRunnable; + if (runnable.failed) return; + runnable.clearTimeout(); + err.uncaught = true; + this.fail(runnable, err); + + // recover from test + if ('test' == runnable.type) { + this.emit('test end', runnable); + this.hookUp('afterEach', this.next); + return; + } + + // bail on hooks + this.emit('end'); +}; + /** * Run the root suite and invoke `fn(failures)` * on completion. @@ -384,9 +410,9 @@ Runner.prototype.run = function(fn){ debug('start'); // callback - self.on('end', function(){ + this.on('end', function(){ debug('end'); - process.removeListener('uncaughtException', uncaught); + process.removeListener('uncaughtException', this.uncaught); fn(self.failures); }); @@ -398,25 +424,9 @@ Runner.prototype.run = function(fn){ }); // uncaught exception - function uncaught(err){ - var runnable = self.currentRunnable; - debug('uncaught exception'); - if (runnable.failed) return; - runnable.clearTimeout(); - err.uncaught = true; - self.fail(runnable, err); - - // recover from test - if ('test' == runnable.type) { - self.emit('test end', runnable); - self.hookUp('afterEach', self.next); - // bail on hooks - } else { - self.emit('end'); - } - } - - process.on('uncaughtException', uncaught); + process.on('uncaughtException', function(err){ + self.uncaught(err); + }); return this; }; diff --git a/package.json b/package.json index fcc6d88b9a..88c578f226 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,6 @@ , "debug": "*" } , "devDependencies": { - "should": "0.4.x" + "should": "*" } } diff --git a/test/runner.js b/test/runner.js new file mode 100644 index 0000000000..8fa6a2e212 --- /dev/null +++ b/test/runner.js @@ -0,0 +1,105 @@ + +var mocha = require('../') + , Suite = mocha.Suite + , Runner = mocha.Runner; + +describe('Runner', function(){ + var suite, runner; + + beforeEach(function(){ + suite = new Suite(null, 'root'); + runner = new Runner(suite); + }) + + describe('.globals()', function(){ + it('should default to the known globals', function(){ + runner.globals().length.should.be.above(10); + }) + + it('should white-list globals', function(){ + runner.globals(['foo', 'bar']); + runner.globals().should.include('foo'); + runner.globals().should.include('bar'); + }) + }) + + describe('.checkGlobals(test)', function(){ + it('should emit "fail" when a new global is introduced', function(done){ + runner.checkGlobals(); + foo = 'bar'; + runner.on('fail', function(test, err){ + test.should.equal('im a test'); + err.message.should.equal('global leak detected: foo'); + delete global.foo; + done(); + }); + runner.checkGlobals('im a test'); + }) + + it('should pluralize the error message when several are introduced', function(done){ + runner.checkGlobals(); + foo = 'bar'; + bar = 'baz'; + runner.on('fail', function(test, err){ + test.should.equal('im a test'); + err.message.should.equal('global leaks detected: foo, bar'); + delete global.foo; + delete global.bar; + done(); + }); + runner.checkGlobals('im a test'); + }) + }) + + describe('.fail(test, err)', function(){ + it('should increment .failures', function(){ + runner.failures.should.equal(0); + runner.fail({}, {}); + runner.failures.should.equal(1); + runner.fail({}, {}); + runner.failures.should.equal(2); + }) + + it('should set test.failed to true', function(){ + var test = {}; + runner.fail(test, 'some error'); + test.failed.should.be.true; + }) + + it('should emit "fail"', function(done){ + var test = {}, err = {}; + runner.on('fail', function(test, err){ + test.should.equal(test); + err.should.equal(err); + done(); + }); + runner.fail(test, err); + }) + }) + + describe('.failHook(hoot, err)', function(){ + it('should increment .failures', function(){ + runner.failures.should.equal(0); + runner.failHook({}, {}); + runner.failures.should.equal(1); + runner.failHook({}, {}); + runner.failures.should.equal(2); + }) + + it('should emit "fail"', function(done){ + var hook = {}, err = {}; + runner.on('fail', function(hook, err){ + hook.should.equal(hook); + err.should.equal(err); + done(); + }); + runner.failHook(hook, err); + }) + + it('should emit "end"', function(done){ + var hook = {}, err = {}; + runner.on('end', done); + runner.failHook(hook, err); + }) + }) +}) \ No newline at end of file