From 905e3fc3f9082d8daed8f04f930deb5f282cc910 Mon Sep 17 00:00:00 2001 From: Gregory Huczynski Date: Fri, 13 Nov 2020 12:06:10 +0000 Subject: [PATCH] Enable custom promise error handling through overriding of global.onerror --- spec/core/GlobalErrorsSpec.js | 76 +++++++++++++++++++++++++++++++++++ src/core/GlobalErrors.js | 4 +- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/spec/core/GlobalErrorsSpec.js b/spec/core/GlobalErrorsSpec.js index 16657a7f..38ee5a55 100644 --- a/spec/core/GlobalErrorsSpec.js +++ b/spec/core/GlobalErrorsSpec.js @@ -12,6 +12,23 @@ describe('GlobalErrors', function() { expect(handler).toHaveBeenCalledWith('foo'); }); + it('enables external interception of error by overriding global.onerror', function() { + var fakeGlobal = { onerror: null }, + handler = jasmine.createSpy('errorHandler'), + hijackHandler = jasmine.createSpy('hijackErrorHandler'), + errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); + + errors.install(); + errors.pushListener(handler); + + fakeGlobal.onerror = hijackHandler; + + fakeGlobal.onerror('foo'); + + expect(hijackHandler).toHaveBeenCalledWith('foo'); + expect(handler).not.toHaveBeenCalled(); + }); + it('calls the global error handler with all parameters', function() { var fakeGlobal = { onerror: null }, handler = jasmine.createSpy('errorHandler'), @@ -285,5 +302,64 @@ describe('GlobalErrors', function() { }) ); }); + + describe('Enabling external interception of reported rejections by overriding global.onerror', function() { + it('overriding global.onerror intercepts rejections whose reason is a string', function() { + var fakeGlobal = jasmine.createSpyObj('globalErrors', [ + 'addEventListener' + ]), + handler = jasmine.createSpy('errorHandler'), + hijackHandler = jasmine.createSpy('hijackErrorHandler'), + errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); + + errors.install(); + errors.pushListener(handler); + + fakeGlobal.onerror = hijackHandler; + + var addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1]; + addedListener({ reason: 'nope' }); + + expect(hijackHandler).toHaveBeenCalledWith( + 'Unhandled promise rejection: nope' + ); + expect(handler).not.toHaveBeenCalled(); + }); + + it('overriding global.onerror intercepts rejections whose reason is an Error', function() { + var fakeGlobal = jasmine.createSpyObj('globalErrors', [ + 'addEventListener' + ]), + handler = jasmine.createSpy('errorHandler'), + hijackHandler = jasmine.createSpy('hijackErrorHandler'), + errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); + + errors.install(); + errors.pushListener(handler); + + fakeGlobal.onerror = hijackHandler; + + var addedListener = fakeGlobal.addEventListener.calls.argsFor(0)[1]; + var reason; + + try { + // Throwing ensures that we get a stack property in all browsers + throw new Error('bar'); + } catch (e) { + reason = e; + } + + addedListener({ reason: reason }); + + expect(hijackHandler).toHaveBeenCalledWith( + jasmine.objectContaining({ + jasmineMessage: 'Unhandled promise rejection: Error: bar', + message: reason.message, + stack: reason.stack + }) + ); + expect(handler).not.toHaveBeenCalled(); + }); + }); }); }); diff --git a/src/core/GlobalErrors.js b/src/core/GlobalErrors.js index b79976d9..4e8fb7eb 100644 --- a/src/core/GlobalErrors.js +++ b/src/core/GlobalErrors.js @@ -67,9 +67,9 @@ getJasmineRequireObj().GlobalErrors = function(j$) { if (j$.isError_(event.reason)) { event.reason.jasmineMessage = 'Unhandled promise rejection: ' + event.reason; - onerror(event.reason); + global.onerror(event.reason); } else { - onerror('Unhandled promise rejection: ' + event.reason); + global.onerror('Unhandled promise rejection: ' + event.reason); } };