From 5f8df0848aa52bb0f7a0844bcd3715012a6ecfd6 Mon Sep 17 00:00:00 2001 From: Juerg B <44573692+juergba@users.noreply.github.com> Date: Thu, 26 Sep 2019 07:32:14 +0200 Subject: [PATCH] uncaughtException: fix double EVENT_RUN_END events (#4025) abort runner instead of end event --- lib/runner.js | 2 +- .../fixtures/regression/issue-1327.fixture.js | 8 +++--- .../fixtures/uncaught-fatal.fixture.js | 25 +++++++++++++------ test/integration/regression.spec.js | 21 ++++++---------- test/integration/uncaught.spec.js | 21 ++++++---------- test/unit/runner.spec.js | 5 ++-- 6 files changed, 41 insertions(+), 41 deletions(-) diff --git a/lib/runner.js b/lib/runner.js index d8d8dd6fb8..e4bb329af3 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -860,7 +860,7 @@ Runner.prototype.uncaught = function(err) { } // bail - this.emit(constants.EVENT_RUN_END); + this.abort(); }; /** diff --git a/test/integration/fixtures/regression/issue-1327.fixture.js b/test/integration/fixtures/regression/issue-1327.fixture.js index e788278d6d..80c8eff0a5 100644 --- a/test/integration/fixtures/regression/issue-1327.fixture.js +++ b/test/integration/fixtures/regression/issue-1327.fixture.js @@ -1,17 +1,17 @@ 'use strict'; +// we cannot recover gracefully if a Runnable has already passed +// then fails asynchronously it('test 1', function () { - console.log('testbody1'); process.nextTick(function () { throw new Error('Too bad'); }); }); it('test 2', function () { - console.log('testbody2'); + throw new Error('should not run - test 2'); }); it('test 3', function () { - console.log('testbody3'); - throw new Error('OUCH'); + throw new Error('should not run - test 3'); }); diff --git a/test/integration/fixtures/uncaught-fatal.fixture.js b/test/integration/fixtures/uncaught-fatal.fixture.js index 10be283816..0419b441df 100644 --- a/test/integration/fixtures/uncaught-fatal.fixture.js +++ b/test/integration/fixtures/uncaught-fatal.fixture.js @@ -1,11 +1,22 @@ 'use strict'; -it('should bail if a successful test asynchronously fails', function(done) { - done(); - process.nextTick(function () { - throw new Error('global error'); - }); -}); +describe('fatal uncaught exception', function () { + describe('first suite', function () { + it('should bail if a successful test asynchronously fails', function (done) { + done(); + process.nextTick(function () { + throw new Error('global error'); + }); + }); -it('should not actually get run', function () { + it('should not actually get run', function () { + throw new Error('should never throw - first suite'); + }); + }); + + describe('second suite', function () { + it('should not actually get run', function () { + throw new Error('should never throw - second suite'); + }); + }); }); diff --git a/test/integration/regression.spec.js b/test/integration/regression.spec.js index ae4f4fba59..0682cdc353 100644 --- a/test/integration/regression.spec.js +++ b/test/integration/regression.spec.js @@ -4,22 +4,17 @@ var run = require('./helpers').runMocha; var runJSON = require('./helpers').runMochaJSON; describe('regressions', function() { - it('issue-1327: should run all 3 specs exactly once', function(done) { + it('issue-1327: should run the first test and then bail', function(done) { var args = []; - run('regression/issue-1327.fixture.js', args, function(err, res) { - var occurences = function(str) { - var pattern = new RegExp(str, 'g'); - return (res.output.match(pattern) || []).length; - }; - + runJSON('regression/issue-1327.fixture.js', args, function(err, res) { if (err) { - done(err); - return; + return done(err); } - expect(res, 'to have failed'); - expect(occurences('testbody1'), 'to be', 1); - expect(occurences('testbody2'), 'to be', 1); - expect(occurences('testbody3'), 'to be', 1); + expect(res, 'to have failed') + .and('to have passed test count', 1) + .and('to have failed test count', 1) + .and('to have passed test', 'test 1') + .and('to have failed test', 'test 1'); done(); }); }); diff --git a/test/integration/uncaught.spec.js b/test/integration/uncaught.spec.js index 42342923f0..a65c4b5097 100644 --- a/test/integration/uncaught.spec.js +++ b/test/integration/uncaught.spec.js @@ -50,23 +50,16 @@ describe('uncaught exceptions', function() { it('handles uncaught exceptions from which Mocha cannot recover', function(done) { run('uncaught-fatal.fixture.js', args, function(err, res) { if (err) { - done(err); - return; + return done(err); } - assert.strictEqual(res.stats.pending, 0); - assert.strictEqual(res.stats.passes, 1); - assert.strictEqual(res.stats.failures, 1); - assert.strictEqual( - res.failures[0].title, - 'should bail if a successful test asynchronously fails' - ); - assert.strictEqual( - res.passes[0].title, - 'should bail if a successful test asynchronously fails' - ); + var testName = 'should bail if a successful test asynchronously fails'; + expect(res, 'to have failed') + .and('to have passed test count', 1) + .and('to have failed test count', 1) + .and('to have passed test', testName) + .and('to have failed test', testName); - assert.strictEqual(res.code, 1); done(); }); }); diff --git a/test/unit/runner.spec.js b/test/unit/runner.spec.js index 31ac938b1f..67043a98bb 100644 --- a/test/unit/runner.spec.js +++ b/test/unit/runner.spec.js @@ -831,15 +831,16 @@ describe('Runner', function() { ]).and('was called once'); }); - it('should notify run has ended', function() { + it('should abort the runner without emitting end event', function() { expect( function() { runner.uncaught(err); }, - 'to emit from', + 'not to emit from', runner, 'end' ); + expect(runner._abort, 'to be', true); }); });