diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 63da8ffa..a0b8a1c3 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -4133,7 +4133,22 @@ getJasmineRequireObj().GlobalErrors = function(j$) { this.jasmineHandlers = {}; this.installOne_ = function installOne_(errorType, jasmineMessage) { function taggedOnError(error) { - error.jasmineMessage = jasmineMessage + ': ' + error; + var substituteMsg; + + if (error) { + error.jasmineMessage = jasmineMessage + ': ' + error; + } else { + substituteMsg = jasmineMessage + ' with no error or message'; + + if (errorType === 'unhandledRejection') { + substituteMsg += + '\n' + + '(Tip: to get a useful stack trace, use ' + + 'Promise.reject(new Error(...)) instead of Promise.reject().)'; + } + + error = new Error(substituteMsg); + } var handler = handlers[handlers.length - 1]; diff --git a/spec/core/GlobalErrorsSpec.js b/spec/core/GlobalErrorsSpec.js index 4fb41c21..8e3ffbc5 100644 --- a/spec/core/GlobalErrorsSpec.js +++ b/spec/core/GlobalErrorsSpec.js @@ -122,7 +122,7 @@ describe('GlobalErrors', function() { errors.uninstall(); }); - it('reports uncaughtException in node.js', function() { + it('reports uncaught exceptions in node.js', function() { var fakeGlobal = { process: { on: jasmine.createSpy('process.on'), @@ -170,7 +170,7 @@ describe('GlobalErrors', function() { ); }); - it('reports unhandledRejection in node.js', function() { + it('reports unhandled promise rejections in node.js', function() { var fakeGlobal = { process: { on: jasmine.createSpy('process.on'), @@ -218,6 +218,38 @@ describe('GlobalErrors', function() { ); }); + it('reports unhandled promise rejections in node.js when no error is provided', function() { + var fakeGlobal = { + process: { + on: jasmine.createSpy('process.on'), + removeListener: function() {}, + listeners: function() { + return []; + }, + removeAllListeners: function() {} + } + }, + handler = jasmine.createSpy('errorHandler'), + errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); + + errors.install(); + errors.pushListener(handler); + + expect(fakeGlobal.process.on.calls.argsFor(1)[0]).toEqual( + 'unhandledRejection' + ); + var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1]; + addedListener(undefined); + + expect(handler).toHaveBeenCalledWith( + new Error( + 'Unhandled promise rejection with no error or message\n' + + '(Tip: to get a useful stack trace, use ' + + 'Promise.reject(new Error(...)) instead of Promise.reject().)' + ) + ); + }); + describe('Reporting unhandled promise rejections in the browser', function() { it('subscribes and unsubscribes from the unhandledrejection event', function() { var fakeGlobal = jasmine.createSpyObj('globalErrors', [ diff --git a/src/core/GlobalErrors.js b/src/core/GlobalErrors.js index f0253b2d..b0c6e20e 100644 --- a/src/core/GlobalErrors.js +++ b/src/core/GlobalErrors.js @@ -17,7 +17,22 @@ getJasmineRequireObj().GlobalErrors = function(j$) { this.jasmineHandlers = {}; this.installOne_ = function installOne_(errorType, jasmineMessage) { function taggedOnError(error) { - error.jasmineMessage = jasmineMessage + ': ' + error; + var substituteMsg; + + if (error) { + error.jasmineMessage = jasmineMessage + ': ' + error; + } else { + substituteMsg = jasmineMessage + ' with no error or message'; + + if (errorType === 'unhandledRejection') { + substituteMsg += + '\n' + + '(Tip: to get a useful stack trace, use ' + + 'Promise.reject(new Error(...)) instead of Promise.reject().)'; + } + + error = new Error(substituteMsg); + } var handler = handlers[handlers.length - 1];