Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit a435740

Browse files
author
Thomas Grainger
committed
fix(*): correctly detect Error instances from different contexts
12345678901234567890123456789012345678901234567890123456789012345678901234567890 Errors thrown from different contexts (such as an iframe or webworker) are not detected as Error instances and handled accordingly. This commit fixes it by introducing an isError() helper, that is able to correctly detect such instances. Fixes #15868
1 parent dcc57f1 commit a435740

File tree

8 files changed

+62
-4
lines changed

8 files changed

+62
-4
lines changed

src/.eslintrc.json

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"isNumber": false,
5151
"isNumberNaN": false,
5252
"isDate": false,
53+
"isError": false,
5354
"isArray": false,
5455
"isFunction": false,
5556
"isRegExp": false,

src/Angular.js

+19
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
isNumber,
4646
isNumberNaN,
4747
isDate,
48+
isError,
4849
isArray,
4950
isFunction,
5051
isRegExp,
@@ -673,6 +674,24 @@ function isDate(value) {
673674
*/
674675
var isArray = Array.isArray;
675676

677+
/**
678+
* @description
679+
* Determines if a reference is an `Error`.
680+
* Loosely based on https://www.npmjs.com/package/iserror
681+
*
682+
* @param {*} value Reference to check.
683+
* @returns {boolean} True if `value` is an `Error`.
684+
*/
685+
function isError(value) {
686+
var tag = toString.call(value);
687+
switch (tag) {
688+
case '[object Error]': return true;
689+
case '[object Exception]': return true;
690+
case '[object DOMException]': return true;
691+
default: return value instanceof Error;
692+
}
693+
}
694+
676695
/**
677696
* @ngdoc function
678697
* @name angular.isFunction

src/ng/compile.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3098,7 +3098,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
30983098
}
30993099
linkQueue = null;
31003100
}).catch(function(error) {
3101-
if (error instanceof Error) {
3101+
if (isError(error)) {
31023102
$exceptionHandler(error);
31033103
}
31043104
});

src/ng/log.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ function $LogProvider() {
132132
};
133133

134134
function formatError(arg) {
135-
if (arg instanceof Error) {
135+
if (isError(arg)) {
136136
if (arg.stack && formatStackTrace) {
137137
arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
138138
? 'Error: ' + arg.message + '\n' + arg.stack

src/ng/q.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
381381
if (!toCheck.pur) {
382382
toCheck.pur = true;
383383
var errorMessage = 'Possibly unhandled rejection: ' + toDebugString(toCheck.value);
384-
if (toCheck.value instanceof Error) {
384+
if (isError(toCheck.value)) {
385385
exceptionHandler(toCheck.value, errorMessage);
386386
} else {
387387
exceptionHandler(errorMessage);

test/.eslintrc.json

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"isNumber": false,
6565
"isNumberNaN": false,
6666
"isDate": false,
67+
"isError": false,
6768
"isArray": false,
6869
"isFunction": false,
6970
"isRegExp": false,

test/AngularSpec.js

+37
Original file line numberDiff line numberDiff line change
@@ -1880,6 +1880,43 @@ describe('angular', function() {
18801880
});
18811881
});
18821882

1883+
describe('isError', function() {
1884+
function testErrorFromDifferentContext(createError) {
1885+
var iframe = document.createElement('iframe');
1886+
document.body.appendChild(iframe);
1887+
try {
1888+
var error = createError(iframe.contentWindow);
1889+
expect(isError(error)).toBe(true);
1890+
} finally {
1891+
iframe.parentElement.removeChild(iframe);
1892+
}
1893+
}
1894+
1895+
it('should not assume objects are errors', function() {
1896+
var fakeError = { message: 'A fake error', stack: 'no stack here'};
1897+
expect(isError(fakeError)).toBe(false);
1898+
});
1899+
1900+
it('should detect simple error instances', function() {
1901+
expect(isError(new Error())).toBe(true);
1902+
});
1903+
1904+
it('should detect errors from another context', function() {
1905+
testErrorFromDifferentContext(function(win) {
1906+
return new win.Error();
1907+
});
1908+
});
1909+
1910+
it('should detect DOMException errors from another context', function() {
1911+
testErrorFromDifferentContext(function(win) {
1912+
try {
1913+
win.document.querySelectorAll('');
1914+
} catch (e) {
1915+
return e;
1916+
}
1917+
});
1918+
});
1919+
});
18831920

18841921
describe('isRegExp', function() {
18851922
it('should return true for RegExp object', function() {

test/ng/qSpec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe('q', function() {
3737
// The following private functions are used to help with logging for testing invocation of the
3838
// promise callbacks.
3939
function _argToString(arg) {
40-
return (typeof arg === 'object' && !(arg instanceof Error)) ? toJson(arg) : '' + arg;
40+
return (typeof arg === 'object' && !(isError(arg))) ? toJson(arg) : '' + arg;
4141
}
4242

4343
function _argumentsToString(args) {

0 commit comments

Comments
 (0)