796 lines
24 KiB
JavaScript
796 lines
24 KiB
JavaScript
describe('GlobalErrors', function() {
|
|
it('calls the added handler on error', function() {
|
|
const globals = browserGlobals();
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
const error = new Error('nope');
|
|
dispatchEvent(globals.listeners, 'error', { error });
|
|
|
|
expect(handler).toHaveBeenCalledWith(jasmine.is(error));
|
|
});
|
|
|
|
it('is not affected by overriding global.onerror', function() {
|
|
const globals = browserGlobals();
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
globals.global.onerror = () => {};
|
|
|
|
const error = new Error('nope');
|
|
dispatchEvent(globals.listeners, 'error', { error });
|
|
|
|
expect(handler).toHaveBeenCalledWith(jasmine.is(error));
|
|
});
|
|
|
|
it('only calls the most recent handler', function() {
|
|
const globals = browserGlobals();
|
|
const handler1 = jasmine.createSpy('errorHandler1');
|
|
const handler2 = jasmine.createSpy('errorHandler2');
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
|
|
errors.install();
|
|
errors.pushListener(handler1);
|
|
errors.pushListener(handler2);
|
|
|
|
const error = new Error('nope');
|
|
dispatchEvent(globals.listeners, 'error', { error });
|
|
|
|
expect(handler1).not.toHaveBeenCalled();
|
|
expect(handler2).toHaveBeenCalledWith(jasmine.is(error));
|
|
});
|
|
|
|
it('calls previous handlers when one is removed', function() {
|
|
const globals = browserGlobals();
|
|
const handler1 = jasmine.createSpy('errorHandler1');
|
|
const handler2 = jasmine.createSpy('errorHandler2');
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
|
|
errors.install();
|
|
errors.pushListener(handler1);
|
|
errors.pushListener(handler2);
|
|
|
|
errors.popListener(handler2);
|
|
|
|
const error = new Error('nope');
|
|
dispatchEvent(globals.listeners, 'error', { error });
|
|
|
|
expect(handler1).toHaveBeenCalledWith(jasmine.is(error));
|
|
expect(handler2).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('throws when no listener is passed to #popListener', function() {
|
|
const errors = new privateUnderTest.GlobalErrors({});
|
|
expect(function() {
|
|
errors.popListener();
|
|
}).toThrowError('popListener expects a listener');
|
|
});
|
|
|
|
it('uninstalls itself', function() {
|
|
const globals = browserGlobals();
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
function unrelatedListener() {}
|
|
|
|
errors.install();
|
|
globals.global.addEventListener('error', unrelatedListener);
|
|
errors.uninstall();
|
|
|
|
expect(globals.listeners.error).toEqual([unrelatedListener]);
|
|
});
|
|
|
|
it('rethrows the original error when there is no handler', function() {
|
|
const globals = browserGlobals();
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
const originalError = new Error('nope');
|
|
|
|
errors.install();
|
|
|
|
try {
|
|
dispatchEvent(globals.listeners, 'error', { error: originalError });
|
|
} catch (e) {
|
|
expect(e).toBe(originalError);
|
|
}
|
|
|
|
errors.uninstall();
|
|
});
|
|
|
|
it("reports browser error events that don't have errors", function() {
|
|
const globals = browserGlobals();
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
const event = {
|
|
message: 'Uncaught SyntaxError: Unexpected end of input',
|
|
error: undefined,
|
|
filename: 'borkenSpec.js',
|
|
lineno: 42
|
|
};
|
|
dispatchEvent(globals.listeners, 'error', event);
|
|
|
|
expect(handler).toHaveBeenCalledWith({
|
|
message: 'Uncaught SyntaxError: Unexpected end of input',
|
|
filename: 'borkenSpec.js',
|
|
lineno: 42,
|
|
stack: '@borkenSpec.js:42'
|
|
});
|
|
});
|
|
|
|
it('reports uncaught exceptions in node.js', function() {
|
|
const globals = nodeGlobals();
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
function originalHandler() {}
|
|
globals.listeners.uncaughtException = [originalHandler];
|
|
|
|
errors.install();
|
|
expect(globals.listeners.uncaughtException).toEqual([
|
|
jasmine.any(Function)
|
|
]);
|
|
expect(globals.listeners.uncaughtException).not.toEqual([
|
|
originalHandler()
|
|
]);
|
|
|
|
errors.pushListener(handler);
|
|
|
|
dispatchEvent(globals.listeners, 'uncaughtException', new Error('bar'));
|
|
|
|
expect(handler).toHaveBeenCalledWith(new Error('bar'));
|
|
expect(handler.calls.argsFor(0)[0].jasmineMessage).toBe(
|
|
'Uncaught exception: Error: bar'
|
|
);
|
|
|
|
errors.uninstall();
|
|
|
|
expect(globals.listeners.uncaughtException).toEqual([originalHandler]);
|
|
});
|
|
|
|
describe('Reporting unhandled promise rejections in node.js', function() {
|
|
it('reports rejections with `Error` reasons', function() {
|
|
const globals = nodeGlobals();
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
function originalHandler() {}
|
|
globals.listeners.unhandledRejection = [originalHandler];
|
|
|
|
errors.install();
|
|
expect(globals.listeners.unhandledRejection).toEqual([
|
|
jasmine.any(Function)
|
|
]);
|
|
expect(globals.listeners.unhandledRejection).not.toEqual([
|
|
originalHandler()
|
|
]);
|
|
|
|
errors.pushListener(handler);
|
|
|
|
dispatchEvent(globals.listeners, 'unhandledRejection', new Error('bar'));
|
|
|
|
expect(handler).toHaveBeenCalledWith(new Error('bar'));
|
|
expect(handler.calls.argsFor(0)[0].jasmineMessage).toBe(
|
|
'Unhandled promise rejection: Error: bar'
|
|
);
|
|
|
|
errors.uninstall();
|
|
|
|
expect(globals.listeners.unhandledRejection).toEqual([originalHandler]);
|
|
});
|
|
|
|
it('reports rejections with non-`Error` reasons', function() {
|
|
const globals = nodeGlobals();
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
dispatchEvent(globals.listeners, 'unhandledRejection', 17);
|
|
|
|
expect(handler).toHaveBeenCalledWith(
|
|
new Error(
|
|
'Unhandled promise rejection: 17\n' +
|
|
'(Tip: to get a useful stack trace, use ' +
|
|
'Promise.reject(new Error(...)) instead of Promise.reject(...).)'
|
|
)
|
|
);
|
|
});
|
|
|
|
it('reports rejections with no reason provided', function() {
|
|
const globals = nodeGlobals();
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
dispatchEvent(globals.listeners, 'unhandledRejection', 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('When detectLateRejectionHandling is true', function() {
|
|
let globals, errors;
|
|
|
|
beforeEach(function() {
|
|
globals = nodeGlobals();
|
|
errors = new privateUnderTest.GlobalErrors(globals.global, () => ({
|
|
detectLateRejectionHandling: true
|
|
}));
|
|
});
|
|
|
|
it('subscribes and unsubscribes from the rejectionHandled event', function() {
|
|
function originalHandler() {}
|
|
globals.global.process.on('rejectionHandled', originalHandler);
|
|
errors.install();
|
|
|
|
expect(globals.listeners.rejectionHandled).toEqual([
|
|
jasmine.any(Function)
|
|
]);
|
|
expect(globals.listeners.rejectionHandled).not.toEqual([
|
|
originalHandler
|
|
]);
|
|
|
|
errors.uninstall();
|
|
expect(globals.listeners.rejectionHandled).toEqual([originalHandler]);
|
|
});
|
|
|
|
describe("When the unhandledRejection event doesn't have a promise", function() {
|
|
it('immediately reports the rejection', function() {
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
dispatchEvent(
|
|
globals.listeners,
|
|
'unhandledRejection',
|
|
new Error('nope'),
|
|
undefined
|
|
);
|
|
|
|
expect(handler).toHaveBeenCalledWith(new Error('nope'));
|
|
expect(handler.calls.argsFor(0)[0].jasmineMessage).toBe(
|
|
'Unhandled promise rejection: Error: nope'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('When the unhandledRejection event has a promise property', function() {
|
|
it('does not immediately report the rejection', function() {
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
const promise = Promise.reject('nope');
|
|
promise.catch(() => {});
|
|
dispatchEvent(
|
|
globals.listeners,
|
|
'unhandledRejection',
|
|
'nope',
|
|
promise
|
|
);
|
|
|
|
expect(handler).not.toHaveBeenCalled();
|
|
});
|
|
|
|
describe('When reportUnhandledRejections is called', function() {
|
|
it('reports rejections that have not been handled', function() {
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
const reason = new Error('nope');
|
|
const promise = Promise.reject(reason);
|
|
promise.catch(() => {});
|
|
dispatchEvent(
|
|
globals.listeners,
|
|
'unhandledRejection',
|
|
reason,
|
|
promise
|
|
);
|
|
errors.reportUnhandledRejections();
|
|
|
|
expect(handler).toHaveBeenCalledWith(new Error('nope'));
|
|
expect(handler.calls.argsFor(0)[0].jasmineMessage).toBe(
|
|
'Unhandled promise rejection: Error: nope'
|
|
);
|
|
});
|
|
|
|
it('does not report rejections that have been handled', function() {
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
const reason = new Error('nope');
|
|
const promise = Promise.reject(reason);
|
|
promise.catch(() => {});
|
|
dispatchEvent(
|
|
globals.listeners,
|
|
'unhandledRejection',
|
|
reason,
|
|
promise
|
|
);
|
|
dispatchEvent(globals.listeners, 'rejectionHandled', promise);
|
|
errors.reportUnhandledRejections();
|
|
|
|
expect(handler).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('does not report the same rejection on subsequent calls', function() {
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
const promise = Promise.reject('nope');
|
|
promise.catch(() => {});
|
|
dispatchEvent(
|
|
globals.listeners,
|
|
'unhandledRejection',
|
|
'nope',
|
|
promise
|
|
);
|
|
errors.reportUnhandledRejections();
|
|
expect(handler).toHaveBeenCalled();
|
|
handler.calls.reset();
|
|
|
|
errors.reportUnhandledRejections();
|
|
expect(handler).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Reporting unhandled promise rejections in the browser', function() {
|
|
it('subscribes and unsubscribes from the unhandledrejection event', function() {
|
|
const globals = browserGlobals();
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
|
|
errors.install();
|
|
expect(globals.listeners.unhandledrejection).toEqual([
|
|
jasmine.any(Function)
|
|
]);
|
|
|
|
errors.uninstall();
|
|
expect(globals.listeners.unhandledrejection).toEqual([]);
|
|
});
|
|
|
|
it('reports rejections whose reason is a string', function() {
|
|
const globals = browserGlobals();
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
const event = { reason: 'nope' };
|
|
dispatchEvent(globals.listeners, 'unhandledrejection', event);
|
|
|
|
expect(handler).toHaveBeenCalledWith('Unhandled promise rejection: nope');
|
|
});
|
|
|
|
it('reports rejections whose reason is an Error', function() {
|
|
const globals = browserGlobals();
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
const reason = new Error('bar');
|
|
const event = { reason };
|
|
dispatchEvent(globals.listeners, 'unhandledrejection', event);
|
|
|
|
expect(handler).toHaveBeenCalledTimes(1);
|
|
const received = handler.calls.argsFor(0)[0];
|
|
expect(received).toBeInstanceOf(Error);
|
|
expect(received).toEqual(
|
|
jasmine.objectContaining({
|
|
jasmineMessage: 'Unhandled promise rejection: Error: bar',
|
|
message: reason.message,
|
|
stack: reason.stack
|
|
})
|
|
);
|
|
});
|
|
|
|
describe('When detectLateRejectionHandling is true', function() {
|
|
let globals, errors;
|
|
|
|
beforeEach(function() {
|
|
globals = browserGlobals();
|
|
errors = new privateUnderTest.GlobalErrors(globals.global, () => ({
|
|
detectLateRejectionHandling: true
|
|
}));
|
|
});
|
|
|
|
it('subscribes and unsubscribes from the rejectionhandled event', function() {
|
|
errors.install();
|
|
expect(globals.listeners.rejectionhandled).toEqual([
|
|
jasmine.any(Function)
|
|
]);
|
|
|
|
errors.uninstall();
|
|
expect(globals.listeners.rejectionhandled).toEqual([]);
|
|
});
|
|
|
|
describe("When the unhandledrejection event doesn't have a promise property", function() {
|
|
it('immediately reports the rejection', function() {
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
const event = { reason: 'nope' };
|
|
dispatchEvent(globals.listeners, 'unhandledrejection', event);
|
|
|
|
expect(handler).toHaveBeenCalledWith(
|
|
'Unhandled promise rejection: nope'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('When the unhandledrejection event has a promise property', function() {
|
|
it('does not immediately report the rejection', function() {
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
const promise = Promise.reject('nope');
|
|
promise.catch(() => {});
|
|
dispatchEvent(globals.listeners, 'unhandledrejection', {
|
|
reason: 'nope',
|
|
promise
|
|
});
|
|
|
|
expect(handler).not.toHaveBeenCalled();
|
|
});
|
|
|
|
describe('When reportUnhandledRejections is called', function() {
|
|
it('reports rejections that have not been handled', function() {
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
const promise = Promise.reject('nope');
|
|
promise.catch(() => {});
|
|
dispatchEvent(globals.listeners, 'unhandledrejection', {
|
|
reason: 'nope',
|
|
promise
|
|
});
|
|
errors.reportUnhandledRejections();
|
|
|
|
expect(handler).toHaveBeenCalledWith(
|
|
'Unhandled promise rejection: nope'
|
|
);
|
|
});
|
|
|
|
it('does not report rejections that have been handled', function() {
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
const promise = Promise.reject('nope');
|
|
promise.catch(() => {});
|
|
dispatchEvent(globals.listeners, 'unhandledrejection', {
|
|
reason: 'nope',
|
|
promise
|
|
});
|
|
dispatchEvent(globals.listeners, 'rejectionhandled', { promise });
|
|
errors.reportUnhandledRejections();
|
|
|
|
expect(handler).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('does not report the same rejection on subsequent calls', function() {
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
const promise = Promise.reject('nope');
|
|
promise.catch(() => {});
|
|
dispatchEvent(globals.listeners, 'unhandledrejection', {
|
|
reason: 'nope',
|
|
promise
|
|
});
|
|
errors.reportUnhandledRejections();
|
|
expect(handler).toHaveBeenCalled();
|
|
handler.calls.reset();
|
|
|
|
errors.reportUnhandledRejections();
|
|
expect(handler).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Reporting uncaught exceptions in node.js', function() {
|
|
it('prepends a descriptive message when the error is not an `Error`', function() {
|
|
const globals = nodeGlobals();
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
dispatchEvent(globals.listeners, 'uncaughtException', 17);
|
|
|
|
expect(handler).toHaveBeenCalledWith(new Error('Uncaught exception: 17'));
|
|
});
|
|
|
|
it('substitutes a descriptive message when the error is falsy', function() {
|
|
const globals = nodeGlobals();
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
const handler = jasmine.createSpy('errorHandler');
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
|
|
dispatchEvent(globals.listeners, 'uncaughtException', undefined);
|
|
|
|
expect(handler).toHaveBeenCalledWith(
|
|
new Error('Uncaught exception with no error or message')
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('#setOverrideListener', function() {
|
|
it('overrides the existing handlers in browsers until removed', function() {
|
|
const globals = browserGlobals();
|
|
const handler0 = jasmine.createSpy('handler0');
|
|
const handler1 = jasmine.createSpy('handler1');
|
|
const overrideHandler = jasmine.createSpy('overrideHandler');
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
|
|
errors.install();
|
|
errors.pushListener(handler0);
|
|
errors.setOverrideListener(overrideHandler, () => {});
|
|
errors.pushListener(handler1);
|
|
dispatchEvent(globals.listeners, 'error', { error: 'foo' });
|
|
|
|
expect(overrideHandler).toHaveBeenCalledWith('foo');
|
|
expect(handler0).not.toHaveBeenCalled();
|
|
expect(handler1).not.toHaveBeenCalled();
|
|
|
|
errors.removeOverrideListener();
|
|
|
|
const event = { error: 'baz' };
|
|
dispatchEvent(globals.listeners, 'error', event);
|
|
expect(overrideHandler).not.toHaveBeenCalledWith('baz');
|
|
expect(handler1).toHaveBeenCalledWith('baz');
|
|
});
|
|
|
|
it('overrides the existing handlers in Node until removed', function() {
|
|
const globals = nodeGlobals();
|
|
const handler0 = jasmine.createSpy('handler0');
|
|
const handler1 = jasmine.createSpy('handler1');
|
|
const overrideHandler = jasmine.createSpy('overrideHandler');
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
|
|
errors.install();
|
|
errors.pushListener(handler0);
|
|
errors.setOverrideListener(overrideHandler);
|
|
errors.pushListener(handler1);
|
|
|
|
dispatchEvent(globals.listeners, 'uncaughtException', new Error('foo'));
|
|
|
|
expect(overrideHandler).toHaveBeenCalledWith(new Error('foo'));
|
|
expect(handler0).not.toHaveBeenCalled();
|
|
expect(handler1).not.toHaveBeenCalled();
|
|
|
|
overrideHandler.calls.reset();
|
|
errors.removeOverrideListener();
|
|
|
|
dispatchEvent(globals.listeners, 'uncaughtException', new Error('bar'));
|
|
expect(overrideHandler).not.toHaveBeenCalled();
|
|
expect(handler1).toHaveBeenCalledWith(new Error('bar'));
|
|
});
|
|
|
|
it('handles unhandled promise rejections in browsers', function() {
|
|
const globals = browserGlobals();
|
|
const handler = jasmine.createSpy('handler');
|
|
const overrideHandler = jasmine.createSpy('overrideHandler');
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
|
|
errors.install();
|
|
errors.pushListener(handler);
|
|
errors.setOverrideListener(overrideHandler, () => {});
|
|
|
|
const reason = new Error('bar');
|
|
|
|
dispatchEvent(globals.listeners, 'unhandledrejection', { reason });
|
|
|
|
expect(overrideHandler).toHaveBeenCalledWith(
|
|
jasmine.objectContaining({
|
|
jasmineMessage: 'Unhandled promise rejection: Error: bar',
|
|
message: reason.message,
|
|
stack: reason.stack
|
|
})
|
|
);
|
|
expect(handler).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('handles unhandled promise rejections in Node', function() {
|
|
const globals = nodeGlobals();
|
|
const handler0 = jasmine.createSpy('handler0');
|
|
const handler1 = jasmine.createSpy('handler1');
|
|
const overrideHandler = jasmine.createSpy('overrideHandler');
|
|
const errors = new privateUnderTest.GlobalErrors(
|
|
globals.global,
|
|
() => ({})
|
|
);
|
|
|
|
errors.install();
|
|
errors.pushListener(handler0);
|
|
errors.setOverrideListener(overrideHandler, () => {});
|
|
errors.pushListener(handler1);
|
|
|
|
dispatchEvent(globals.listeners, 'unhandledRejection', new Error('nope'));
|
|
|
|
expect(overrideHandler).toHaveBeenCalledWith(new Error('nope'));
|
|
expect(handler0).not.toHaveBeenCalled();
|
|
expect(handler1).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('throws if there is already an override handler', function() {
|
|
const errors = new privateUnderTest.GlobalErrors(browserGlobals().global);
|
|
|
|
errors.setOverrideListener(() => {}, () => {});
|
|
expect(function() {
|
|
errors.setOverrideListener(() => {}, () => {});
|
|
}).toThrowError("Can't set more than one override listener at a time");
|
|
});
|
|
});
|
|
|
|
describe('#removeOverrideListener', function() {
|
|
it("calls the handler's onRemove callback", function() {
|
|
const onRemove = jasmine.createSpy('onRemove');
|
|
const errors = new privateUnderTest.GlobalErrors(browserGlobals().global);
|
|
|
|
errors.setOverrideListener(() => {}, onRemove);
|
|
errors.removeOverrideListener();
|
|
|
|
expect(onRemove).toHaveBeenCalledWith();
|
|
});
|
|
|
|
it('does not throw if there is no handler', function() {
|
|
const errors = new privateUnderTest.GlobalErrors(browserGlobals().global);
|
|
|
|
expect(() => errors.removeOverrideListener()).not.toThrow();
|
|
});
|
|
});
|
|
|
|
function browserGlobals() {
|
|
const listeners = {
|
|
error: [],
|
|
unhandledrejection: [],
|
|
rejectionhandled: []
|
|
};
|
|
return {
|
|
listeners,
|
|
global: {
|
|
addEventListener(eventName, listener) {
|
|
listeners[eventName].push(listener);
|
|
},
|
|
removeEventListener(eventName, listener) {
|
|
listeners[eventName] = listeners[eventName].filter(
|
|
l => l !== listener
|
|
);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
function nodeGlobals() {
|
|
const listeners = {
|
|
uncaughtException: [],
|
|
unhandledRejection: [],
|
|
rejectionHandled: []
|
|
};
|
|
return {
|
|
listeners,
|
|
global: {
|
|
process: {
|
|
on(eventName, listener) {
|
|
listeners[eventName].push(listener);
|
|
},
|
|
removeListener(eventName, listener) {
|
|
listeners[eventName] = listeners[eventName].filter(
|
|
l => l !== listener
|
|
);
|
|
},
|
|
removeAllListeners(eventName) {
|
|
listeners[eventName] = [];
|
|
},
|
|
listeners(eventName) {
|
|
return listeners[eventName];
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
function dispatchEvent(listeners, eventName, ...args) {
|
|
expect(listeners[eventName].length)
|
|
.withContext(`number of ${eventName} listeners`)
|
|
.toBeGreaterThan(0);
|
|
|
|
for (const l of listeners[eventName]) {
|
|
l.apply(null, args);
|
|
}
|
|
}
|
|
});
|