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(); + }); + }); });