From 67a81245f969267dbb1878c73d593d8316d5706f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Sat, 22 Jun 2024 19:15:23 -0400 Subject: [PATCH] fix: include stack in browser uncaught error reporting (#5107) * Include stack in browser uncaught error reporting * Attempt at testing (failing due to uncaught exception) * Revert "Attempt at testing (failing due to uncaught exception)" This reverts commit 30c7ffb8005937707ee894623d28b054eb621fd8. * implemented test in throw.spec.js & got it passing * Apply suggestions from code review * Update test/unit/throw.spec.js Co-authored-by: Pelle Wessman * test: fix up throw.spec.js --------- Co-authored-by: Peter Rust Co-authored-by: Pelle Wessman --- browser-entry.js | 4 ++-- test/unit/throw.spec.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/browser-entry.js b/browser-entry.js index 67517db357..4e6f9e939a 100644 --- a/browser-entry.js +++ b/browser-entry.js @@ -71,8 +71,8 @@ process.listenerCount = function (name) { 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 + ':' + col + ')')); return !mocha.options.allowUncaught; }; uncaughtExceptionHandlers.push(fn); diff --git a/test/unit/throw.spec.js b/test/unit/throw.spec.js index ccb7ef6c11..cafadaa4bc 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; @@ -29,6 +30,7 @@ describe('a test that throws', function () { uncaughtHandlers.forEach(function (listener) { process.on('uncaughtException', listener); }); + sinon.restore(); }); describe('non-extensible', function () { @@ -172,4 +174,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); + sinon.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(); + }); + }); });