diff --git a/lib/test.js b/lib/test.js index c53abb5a..5edb47fe 100644 --- a/lib/test.js +++ b/lib/test.js @@ -5,6 +5,25 @@ var path = require('path'); var inherits = require('util').inherits; var EventEmitter = require('events').EventEmitter; +/** + * Transitions: + * + * From -> To : Triggered by + * + * PENDING -> RUNNING : Results object calls .run + * RUNNING -> FINISHED : .end no remaining subtest + * RUNNING -> SUBTESTS : .end with subtests + * SUBTESTS -> FINISHED : .end after all subtests end + * + * .end is called when: + * + * - it's called by the test itself + * - there is a plan and: + * - The assertion count + number of children == plan + * + */ + + module.exports = Test; var nextTick = typeof setImmediate !== 'undefined' @@ -36,6 +55,7 @@ function Test (name_, opts_, cb_) { this.readable = true; this.name = name || '(anonymous)'; this.assertCount = 0; + this.pendingCount = 0; this._skip = opts.skip || false; this._plan = undefined; this._cb = cb; @@ -60,9 +80,19 @@ Test.prototype.run = function () { }; Test.prototype.test = function (name, opts, cb) { + var self = this; var t = new Test(name, opts, cb); this._progeny.push(t); + this.pendingCount++; this.emit('test', t); + t.on('prerun', function () { + self.assertCount++; + }) + if (!self._pendingAsserts()) { + nextTick(function () { + self.end(); + }); + } }; Test.prototype.comment = function (msg) { @@ -76,16 +106,19 @@ Test.prototype.plan = function (n) { Test.prototype.end = function () { var self = this; + if (this._progeny.length) { var t = this._progeny.shift(); - t.on('end', function () { self.end() }); + t.on('end', function () { + self.end(); + }); this.emit('next', t); return; } if (!this.ended) this.emit('end'); - if (this._plan !== undefined && - !this._planError && this.assertCount !== this._plan) { + var pendingAsserts = this._pendingAsserts(); + if (!this._planError && this._plan !== undefined && pendingAsserts) { this._planError = true; this.fail('plan != count', { expected : this._plan, @@ -112,6 +145,15 @@ Test.prototype._exit = function () { } }; +Test.prototype._pendingAsserts = function () { + if (this._plan === undefined) { + return 1; + } else { + return this._plan - + (this._progeny.length + this.assertCount); + } +} + Test.prototype._assert = function assert (ok, opts) { var self = this; var extra = opts.extra || {}; @@ -160,20 +202,22 @@ Test.prototype._assert = function assert (ok, opts) { self.emit('result', res); - if (self._plan === self.assertCount && extra.exiting) { - if (!self.ended) self.end(); - } - else if (self._plan === self.assertCount) { - nextTick(function () { - if (!self.ended) self.end(); - }); + var pendingAsserts = self._pendingAsserts(); + if (!pendingAsserts) { + if (extra.exiting) { + self.end(); + } else { + nextTick(function () { + self.end(); + }); + } } - if (!self._planError && self.assertCount > self._plan) { + if (!self._planError && pendingAsserts < 0) { self._planError = true; self.fail('plan != count', { expected : self._plan, - actual : self.assertCount + actual : self._plan - pendingAsserts }); } }; diff --git a/test/nested.js b/test/nested.js index 6af123bc..673465d4 100644 --- a/test/nested.js +++ b/test/nested.js @@ -39,7 +39,7 @@ tap.test('array test', function (tt) { test.createStream().pipe(tc); test('nested array test', function (t) { - t.plan(5); + t.plan(6); var src = '(' + function () { var xs = [ 1, 2, [ 3, 4 ] ]; diff --git a/test/subtest_plan.js b/test/subtest_plan.js index 67a4c464..2b075ae5 100644 --- a/test/subtest_plan.js +++ b/test/subtest_plan.js @@ -15,7 +15,7 @@ test('parent', function (t) { t.test('second child', function (t) { t.plan(2); - t.ok(firstChildRan, 'first child ran'); + t.ok(firstChildRan, 'first child ran first'); t.pass('pass second child'); }); });