Better reporting of unhandled promise rejections with truthy but non-Error reasons on Node

[#179227413]
This commit is contained in:
Steve Gravrock
2021-08-14 14:01:15 -07:00
parent e72d161fab
commit dd8a65cb60
3 changed files with 120 additions and 74 deletions

View File

@@ -4333,16 +4333,22 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
function taggedOnError(error) { function taggedOnError(error) {
var substituteMsg; var substituteMsg;
if (error) { if (j$.isError_(error)) {
error.jasmineMessage = jasmineMessage + ': ' + error; error.jasmineMessage = jasmineMessage + ': ' + error;
} else { } else {
substituteMsg = jasmineMessage + ' with no error or message'; if (error) {
substituteMsg = jasmineMessage + ': ' + error;
} else {
substituteMsg = jasmineMessage + ' with no error or message';
}
if (errorType === 'unhandledRejection') { if (errorType === 'unhandledRejection') {
substituteMsg += substituteMsg +=
'\n' + '\n' +
'(Tip: to get a useful stack trace, use ' + '(Tip: to get a useful stack trace, use ' +
'Promise.reject(new Error(...)) instead of Promise.reject().)'; 'Promise.reject(new Error(...)) instead of Promise.reject(' +
(error ? '...' : '') +
').)';
} }
error = new Error(substituteMsg); error = new Error(substituteMsg);

View File

@@ -170,84 +170,118 @@ describe('GlobalErrors', function() {
); );
}); });
it('reports unhandled promise rejections in node.js', function() { describe('Reporting unhandled promise rejections in node.js', function() {
var fakeGlobal = { it('reports rejections with `Error` reasons', function() {
process: { var fakeGlobal = {
on: jasmine.createSpy('process.on'), process: {
removeListener: jasmine.createSpy('process.removeListener'), on: jasmine.createSpy('process.on'),
listeners: jasmine removeListener: jasmine.createSpy('process.removeListener'),
.createSpy('process.listeners') listeners: jasmine
.and.returnValue(['foo']), .createSpy('process.listeners')
removeAllListeners: jasmine.createSpy('process.removeAllListeners') .and.returnValue(['foo']),
} removeAllListeners: jasmine.createSpy('process.removeAllListeners')
}, }
handler = jasmine.createSpy('errorHandler'), },
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); handler = jasmine.createSpy('errorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install(); errors.install();
expect(fakeGlobal.process.on).toHaveBeenCalledWith( expect(fakeGlobal.process.on).toHaveBeenCalledWith(
'unhandledRejection', 'unhandledRejection',
jasmine.any(Function) jasmine.any(Function)
); );
expect(fakeGlobal.process.listeners).toHaveBeenCalledWith( expect(fakeGlobal.process.listeners).toHaveBeenCalledWith(
'unhandledRejection' 'unhandledRejection'
); );
expect(fakeGlobal.process.removeAllListeners).toHaveBeenCalledWith( expect(fakeGlobal.process.removeAllListeners).toHaveBeenCalledWith(
'unhandledRejection' 'unhandledRejection'
); );
errors.pushListener(handler); errors.pushListener(handler);
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1]; var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
addedListener(new Error('bar')); addedListener(new Error('bar'));
expect(handler).toHaveBeenCalledWith(new Error('bar')); expect(handler).toHaveBeenCalledWith(new Error('bar'));
expect(handler.calls.argsFor(0)[0].jasmineMessage).toBe( expect(handler.calls.argsFor(0)[0].jasmineMessage).toBe(
'Unhandled promise rejection: Error: bar' 'Unhandled promise rejection: Error: bar'
); );
errors.uninstall(); errors.uninstall();
expect(fakeGlobal.process.removeListener).toHaveBeenCalledWith( expect(fakeGlobal.process.removeListener).toHaveBeenCalledWith(
'unhandledRejection', 'unhandledRejection',
addedListener addedListener
); );
expect(fakeGlobal.process.on).toHaveBeenCalledWith( expect(fakeGlobal.process.on).toHaveBeenCalledWith(
'unhandledRejection', 'unhandledRejection',
'foo' 'foo'
); );
}); });
it('reports unhandled promise rejections in node.js when no error is provided', function() { it('reports rejections with non-`Error` reasons', function() {
var fakeGlobal = { var fakeGlobal = {
process: { process: {
on: jasmine.createSpy('process.on'), on: jasmine.createSpy('process.on'),
removeListener: function() {}, removeListener: function() {},
listeners: function() { listeners: function() {
return []; return [];
}, },
removeAllListeners: function() {} removeAllListeners: function() {}
} }
}, },
handler = jasmine.createSpy('errorHandler'), handler = jasmine.createSpy('errorHandler'),
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal); errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
errors.install(); errors.install();
errors.pushListener(handler); errors.pushListener(handler);
expect(fakeGlobal.process.on.calls.argsFor(1)[0]).toEqual( expect(fakeGlobal.process.on.calls.argsFor(1)[0]).toEqual(
'unhandledRejection' 'unhandledRejection'
); );
var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1]; var addedListener = fakeGlobal.process.on.calls.argsFor(1)[1];
addedListener(undefined); addedListener(17);
expect(handler).toHaveBeenCalledWith( expect(handler).toHaveBeenCalledWith(
new Error( new Error(
'Unhandled promise rejection with no error or message\n' + 'Unhandled promise rejection: 17\n' +
'(Tip: to get a useful stack trace, use ' + '(Tip: to get a useful stack trace, use ' +
'Promise.reject(new Error(...)) instead of Promise.reject().)' 'Promise.reject(new Error(...)) instead of Promise.reject(...).)'
) )
); );
});
it('reports rejections with no reason 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() { describe('Reporting unhandled promise rejections in the browser', function() {

View File

@@ -19,16 +19,22 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
function taggedOnError(error) { function taggedOnError(error) {
var substituteMsg; var substituteMsg;
if (error) { if (j$.isError_(error)) {
error.jasmineMessage = jasmineMessage + ': ' + error; error.jasmineMessage = jasmineMessage + ': ' + error;
} else { } else {
substituteMsg = jasmineMessage + ' with no error or message'; if (error) {
substituteMsg = jasmineMessage + ': ' + error;
} else {
substituteMsg = jasmineMessage + ' with no error or message';
}
if (errorType === 'unhandledRejection') { if (errorType === 'unhandledRejection') {
substituteMsg += substituteMsg +=
'\n' + '\n' +
'(Tip: to get a useful stack trace, use ' + '(Tip: to get a useful stack trace, use ' +
'Promise.reject(new Error(...)) instead of Promise.reject().)'; 'Promise.reject(new Error(...)) instead of Promise.reject(' +
(error ? '...' : '') +
').)';
} }
error = new Error(substituteMsg); error = new Error(substituteMsg);