From c94fc46d8c66a86785955ee57959e7d285c9fa8a Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Tue, 11 Jun 2019 13:10:33 -0700 Subject: [PATCH 1/4] Include stack in browser uncaught error reporting --- browser-entry.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/browser-entry.js b/browser-entry.js index fd89117755..148af07012 100644 --- a/browser-entry.js +++ b/browser-entry.js @@ -58,8 +58,8 @@ process.removeListener = function(e, fn) { process.on = function(e, fn) { if (e === 'uncaughtException') { - global.onerror = function(err, url, line) { - fn(new Error(err + ' (' + url + ':' + line + ')')); + global.onerror = function(msg, url, line, col, err) { + fn(err || new Error(msg + ' (' + url + ':' + line + ')')); return !mocha.allowUncaught; }; uncaughtExceptionHandlers.push(fn); From 30c7ffb8005937707ee894623d28b054eb621fd8 Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Wed, 12 Jun 2019 09:42:13 -0700 Subject: [PATCH 2/4] Attempt at testing (failing due to uncaught exception) --- karma.conf.js | 6 ++++- .../uncaught-exception.spec.mjs | 27 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 test/browser-specific/uncaught-exception.spec.mjs diff --git a/karma.conf.js b/karma.conf.js index 82e934bbc7..dedb4a9e68 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -143,7 +143,11 @@ module.exports = config => { pattern: 'test/browser-specific/fixtures/esm.fixture.mjs', type: 'module' }, - {pattern: 'test/browser-specific/esm.spec.mjs', type: 'module'} + {pattern: 'test/browser-specific/esm.spec.mjs', type: 'module'}, + { + pattern: 'test/browser-specific/uncaught-exception.spec.mjs', + type: 'module' + } ]; break; default: diff --git a/test/browser-specific/uncaught-exception.spec.mjs b/test/browser-specific/uncaught-exception.spec.mjs new file mode 100644 index 0000000000..54b852f875 --- /dev/null +++ b/test/browser-specific/uncaught-exception.spec.mjs @@ -0,0 +1,27 @@ +import '/base/mocha.js'; + +var Mocha = window.Mocha; +var Suite = Mocha.Suite; +var Runner = Mocha.Runner; + +mocha.allowUncaught() + +it('should include the stack of uncaught exceptions', function(done) { + var suite = new Suite('Suite', 'root'); + var runner = new Runner(suite); + runner.allowUncaught = true; + var err; + runner.fail = function(e) { + err = e; + }; + + setTimeout(function throwTestError() { + throw new Error('test error'); + }, 1); + + setTimeout(function() { + expect(err, 'to be an', Error); + expect(err.stack, 'to contain', 'at throwTestError') + done(); + }, 2); +}); From d51e79e44a8587f1495934f7bcd2df8131925f8b Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Wed, 12 Jun 2019 12:05:37 -0700 Subject: [PATCH 3/4] Revert "Attempt at testing (failing due to uncaught exception)" This reverts commit 30c7ffb8005937707ee894623d28b054eb621fd8. --- karma.conf.js | 6 +---- .../uncaught-exception.spec.mjs | 27 ------------------- 2 files changed, 1 insertion(+), 32 deletions(-) delete mode 100644 test/browser-specific/uncaught-exception.spec.mjs diff --git a/karma.conf.js b/karma.conf.js index dedb4a9e68..82e934bbc7 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -143,11 +143,7 @@ module.exports = config => { pattern: 'test/browser-specific/fixtures/esm.fixture.mjs', type: 'module' }, - {pattern: 'test/browser-specific/esm.spec.mjs', type: 'module'}, - { - pattern: 'test/browser-specific/uncaught-exception.spec.mjs', - type: 'module' - } + {pattern: 'test/browser-specific/esm.spec.mjs', type: 'module'} ]; break; default: diff --git a/test/browser-specific/uncaught-exception.spec.mjs b/test/browser-specific/uncaught-exception.spec.mjs deleted file mode 100644 index 54b852f875..0000000000 --- a/test/browser-specific/uncaught-exception.spec.mjs +++ /dev/null @@ -1,27 +0,0 @@ -import '/base/mocha.js'; - -var Mocha = window.Mocha; -var Suite = Mocha.Suite; -var Runner = Mocha.Runner; - -mocha.allowUncaught() - -it('should include the stack of uncaught exceptions', function(done) { - var suite = new Suite('Suite', 'root'); - var runner = new Runner(suite); - runner.allowUncaught = true; - var err; - runner.fail = function(e) { - err = e; - }; - - setTimeout(function throwTestError() { - throw new Error('test error'); - }, 1); - - setTimeout(function() { - expect(err, 'to be an', Error); - expect(err.stack, 'to contain', 'at throwTestError') - done(); - }, 2); -}); From b297091292fb81ad2483e40560725e44467d140e Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Wed, 12 Jun 2019 12:06:47 -0700 Subject: [PATCH 4/4] implemented test in throw.spec.js & got it passing --- test/unit/throw.spec.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/unit/throw.spec.js b/test/unit/throw.spec.js index 2dc3c8a759..f7d14c070b 100644 --- a/test/unit/throw.spec.js +++ b/test/unit/throw.spec.js @@ -2,6 +2,7 @@ /* eslint no-throw-literal: off */ +var sinon = require('sinon'); var Mocha = require('../../lib/mocha'); var Suite = Mocha.Suite; var Test = Mocha.Test; @@ -13,11 +14,13 @@ var STATE_FAILED = Runnable.constants.STATE_FAILED; describe('a test that throws', function() { var suite; var runner; + var sandbox; var uncaughtHandlers; beforeEach(function() { suite = new Suite('Suite', 'root'); runner = new Runner(suite); + sandbox = sinon.createSandbox(); // see https://github.com/mochajs/mocha/pull/2983#issuecomment-350428522 uncaughtHandlers = process.listeners('uncaughtException') || []; @@ -169,4 +172,35 @@ describe('a test that throws', function() { runner.run(); }); }); + + describe('stack', function() { + it('should include the stack when throwing async', function(done) { + var test = new Test('im async and throw null async', function(done2) { + process.nextTick(function throwError() { + throw new Error('test error'); + }); + }); + suite.addTest(test); + runner = new Runner(suite); + sandbox.stub(runner, 'fail'); + + runner.on(EVENT_RUN_END, function() { + try { + expect(runner.fail, 'to have all calls satisfying', [ + expect.it('to be a', Runnable), + expect.it('to be an', Error).and('to satisfy', { + message: /test error/i, + stack: /throwError/i, + uncaught: true + }) + ]).and('was called once'); + } catch (err) { + return done(err); + } + + done(); + }); + runner.run(); + }); + }); });