Skip to content

Commit 1dd6336

Browse files
author
Thomas Grainger
committed
fix($q): Add traceback to unhandled promise rejections, Fixes: angular#14631
1 parent f768da2 commit 1dd6336

File tree

2 files changed

+94
-40
lines changed

2 files changed

+94
-40
lines changed

Diff for: src/ng/q.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,11 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
381381
if (!toCheck.pur) {
382382
toCheck.pur = true;
383383
var errorMessage = 'Possibly unhandled rejection: ' + toDebugString(toCheck.value);
384-
exceptionHandler(errorMessage);
384+
if (toCheck.value instanceof Error) {
385+
exceptionHandler(toCheck.value, errorMessage);
386+
} else {
387+
exceptionHandler(errorMessage);
388+
}
385389
}
386390
}
387391
}

Diff for: test/ng/qSpec.js

+89-39
Original file line numberDiff line numberDiff line change
@@ -181,16 +181,14 @@ describe('q', function() {
181181
};
182182

183183

184-
function exceptionHandler(reason) {
185-
exceptionHandlerCalls.push(reason);
186-
}
187-
188-
189-
function exceptionHandlerStr() {
190-
return exceptionHandlerCalls.join('; ');
184+
function exceptionHandler(exception, reason) {
185+
if (typeof reason === 'undefined') {
186+
exceptionHandlerCalls.push({ reason: exception });
187+
} else {
188+
exceptionHandlerCalls.push({ reason: reason, exception: exception });
189+
}
191190
}
192191

193-
194192
beforeEach(function() {
195193
q = qFactory(mockNextTick.nextTick, exceptionHandler, true);
196194
q_no_error = qFactory(mockNextTick.nextTick, exceptionHandler, false);
@@ -2167,45 +2165,97 @@ describe('q', function() {
21672165

21682166

21692167
describe('when exceptionHandler is called', function() {
2170-
it('should log an unhandled rejected promise', function() {
2171-
var defer = q.defer();
2172-
defer.reject('foo');
2173-
mockNextTick.flush();
2174-
expect(exceptionHandlerStr()).toBe('Possibly unhandled rejection: foo');
2175-
});
2168+
function CustomError() { }
2169+
CustomError.prototype = Object.create(Error.prototype);
21762170

2171+
var errorEg = new Error('Fail');
2172+
var errorStr = toDebugString(errorEg);
21772173

2178-
it('should not log an unhandled rejected promise if disabled', function() {
2179-
var defer = q_no_error.defer();
2180-
defer.reject('foo');
2181-
expect(exceptionHandlerStr()).toBe('');
2182-
});
2174+
var customError = new CustomError('Custom');
2175+
var customErrorStr = toDebugString(customError);
21832176

2177+
var nonErrorObj = { isATest: 'this is' };
2178+
var nonErrorObjStr = toDebugString(nonErrorObj);
21842179

2185-
it('should log a handled rejected promise on a promise without rejection callbacks', function() {
2186-
var defer = q.defer();
2187-
defer.promise.then(noop);
2188-
defer.reject('foo');
2189-
mockNextTick.flush();
2190-
expect(exceptionHandlerStr()).toBe('Possibly unhandled rejection: foo');
2191-
});
2180+
var fixtures = [
2181+
{
2182+
type: 'Error object',
2183+
value: errorEg,
2184+
expected: {
2185+
exception: errorEg,
2186+
reason: 'Possibly unhandled rejection: ' + errorStr
2187+
}
2188+
},
2189+
{
2190+
type: 'Custom Error object',
2191+
value: customError,
2192+
expected: {
2193+
exception: customError,
2194+
reason: 'Possibly unhandled rejection: ' + customErrorStr
2195+
}
2196+
},
2197+
{
2198+
type: 'Non-Error object',
2199+
value: nonErrorObj,
2200+
expected: {
2201+
reason: 'Possibly unhandled rejection: ' + nonErrorObjStr
2202+
}
2203+
},
2204+
{
2205+
type: 'plain value',
2206+
value: 'foo',
2207+
expected: {
2208+
reason: 'Possibly unhandled rejection: foo'
2209+
}
2210+
}
2211+
];
2212+
forEach(fixtures, function(fixture) {
2213+
var type = fixture.type;
2214+
var value = fixture.value;
2215+
var expected = fixture.expected;
2216+
describe(type, function() {
2217+
2218+
it('should log an unhandled rejected promise', function() {
2219+
var defer = q.defer();
2220+
defer.reject(value);
2221+
mockNextTick.flush();
2222+
expect(exceptionHandlerCalls).toEqual([expected]);
2223+
});
21922224

21932225

2194-
it('should not log a handled rejected promise', function() {
2195-
var defer = q.defer();
2196-
defer.promise.catch(noop);
2197-
defer.reject('foo');
2198-
mockNextTick.flush();
2199-
expect(exceptionHandlerStr()).toBe('');
2200-
});
2226+
it('should not log an unhandled rejected promise if disabled', function() {
2227+
var defer = q_no_error.defer();
2228+
defer.reject(value);
2229+
expect(exceptionHandlerCalls).toEqual([]);
2230+
});
22012231

22022232

2203-
it('should not log a handled rejected promise that is handled in a future tick', function() {
2204-
var defer = q.defer();
2205-
defer.promise.catch(noop);
2206-
defer.resolve(q.reject('foo'));
2207-
mockNextTick.flush();
2208-
expect(exceptionHandlerStr()).toBe('');
2233+
it('should log a handled rejected promise on a promise without rejection callbacks', function() {
2234+
var defer = q.defer();
2235+
defer.promise.then(noop);
2236+
defer.reject(value);
2237+
mockNextTick.flush();
2238+
expect(exceptionHandlerCalls).toEqual([expected]);
2239+
});
2240+
2241+
2242+
it('should not log a handled rejected promise', function() {
2243+
var defer = q.defer();
2244+
defer.promise.catch(noop);
2245+
defer.reject(value);
2246+
mockNextTick.flush();
2247+
expect(exceptionHandlerCalls).toEqual([]);
2248+
});
2249+
2250+
2251+
it('should not log a handled rejected promise that is handled in a future tick', function() {
2252+
var defer = q.defer();
2253+
defer.promise.catch(noop);
2254+
defer.resolve(q.reject(value));
2255+
mockNextTick.flush();
2256+
expect(exceptionHandlerCalls).toEqual([]);
2257+
});
2258+
});
22092259
});
22102260
});
22112261
});

0 commit comments

Comments
 (0)