diff --git a/lib/runner.js b/lib/runner.js index 241a96fa3..4b76e321b 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -166,18 +166,19 @@ Runner.prototype.serial = function (tests) { }; Runner.prototype._addTestResult = function (test) { - if (test.assertError) { - this.stats.failCount++; - } - var props = { duration: test.duration, title: test.title, - error: test.assertError, + error: undefined, type: test.type, skip: test.skip }; + if (test.assertErrors.length) { + this.stats.failCount++; + props.error = test.assertErrors[0]; + } + this.results.push(props); this.emit('test', props); }; diff --git a/lib/test.js b/lib/test.js index 32cb9a3f0..89c8c902d 100644 --- a/lib/test.js +++ b/lib/test.js @@ -27,6 +27,7 @@ function Test(title, fn) { this.assertCount = 0; this.planCount = null; this.duration = null; + this.assertErrors = []; this.context = {}; // test type, can be: test, hook, eachHook @@ -73,14 +74,14 @@ Object.keys(assert).forEach(function (el) { self._assert(); }) .catch(function (err) { - self.assertError = err; + self.assertErrors.push(err); self._assert(); }); } this._assert(); } catch (err) { - this.assertError = err; + this.assertErrors.push(err); this._assert(); } }; @@ -135,17 +136,17 @@ Test.prototype.run = function () { } }.bind(this)) .catch(function (err) { - this.assertError = new assert.AssertionError({ + this.assertErrors.push(new assert.AssertionError({ actual: err, message: 'Promise rejected → ' + err, operator: 'promise' - }); + })); this.exit(); }.bind(this)); } } catch (err) { - this.assertError = err; + this.assertErrors.push(err); this.exit(); } }.bind(this)); @@ -153,11 +154,11 @@ Test.prototype.run = function () { Test.prototype.end = function (err) { if (err) { - this.assertError = new assert.AssertionError({ + this.assertErrors.push(new assert.AssertionError({ actual: err, message: 'Callback called with an error → ' + err, operator: 'callback' - }); + })); return this.exit(); } @@ -177,23 +178,23 @@ Test.prototype.exit = function () { // stop infinite timer clearTimeout(this._timeout); - if (!this.assertError && this.planCount !== null && this.planCount !== this.assertCount) { - this.assertError = new assert.AssertionError({ + if (this.planCount !== null && this.planCount !== this.assertCount) { + var planError = new assert.AssertionError({ actual: this.assertCount, expected: this.planCount, message: 'Assertion count does not match planned', operator: 'plan' }); - - this.assertError.stack = this.planStack; + planError.stack = this.planStack; + this.assertErrors.push(planError); } if (!this.ended) { this.ended = true; setImmediate(function () { - if (this.assertError) { - return this.promise.reject(this.assertError); + if (this.assertErrors.length) { + return this.promise.reject(this.assertErrors[0]); } this.promise.resolve(this); diff --git a/test/fixture/multiple-assert-errors.js b/test/fixture/multiple-assert-errors.js new file mode 100644 index 000000000..c27eaee28 --- /dev/null +++ b/test/fixture/multiple-assert-errors.js @@ -0,0 +1,11 @@ +import test from '../../'; + +test(t => { + const a = 'foo'; + t.ok(a === 'bar'); + + const b = 'kung'; + t.ok(b === 'foo'); + + t.end(); +}); diff --git a/test/test.js b/test/test.js index a0e1418b6..837736e13 100644 --- a/test/test.js +++ b/test/test.js @@ -1190,6 +1190,18 @@ test('power-assert support', function (t) { }); }); +test('displays first assertion error', function (t) { + t.plan(3); + + execCli('fixture/multiple-assert-errors.js', function (err, stdout, stderr) { + t.ok(err); + + t.true((/t\.ok\(a === 'bar'\)/m).test(stderr)); + // do not show the second by default + t.false((/t\.ok\(b === 'foo'\)/m).test(stderr)); + }); +}); + test('circular references on assertions do not break process.send', function (t) { t.plan(2);