blob: 4176fd1f719947fa69452f296624649e47e4a940 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(function() {
'use strict';
/**
* This variable is checked in several integration and unit tests, to make sure
* that new code changes don't cause unhandled exceptions.
* @type {number}
*/
window.JSErrorCount = 0;
/**
* Count uncaught exceptions.
*/
window.onerror = function(message, url) {
window.JSErrorCount++;
};
/**
* Count uncaught errors in promises.
*/
window.addEventListener('unhandledrejection', (event) => {
console.error(event.reason);
});
/**
* Overrides console.error() to count errors.
*
* @param {...*} args Message and/or objects to be logged.
*/
console.error = (() => {
const orig = console.error;
return (...args) => {
const prefix = '[unhandled-error]: ';
if (args.length) {
args[0] = prefix + args[0];
} else {
args.push(prefix);
}
const stack = new Error('original stack').stack;
args.push(stack);
window.JSErrorCount++;
return orig.apply(this, [args.join('\n')]);
};
})();
/**
* Overrides console.assert() to count errors.
*
* @param {boolean} condition If false, log a message and stack trace.
* @param {...*} args Message and/or objects to be logged when condition is
* false.
*/
console.assert = (() => {
const orig = console.assert;
return (condition, ...args) => {
const stack = new Error('original stack').stack;
args.push(stack);
if (!condition) {
window.JSErrorCount++;
}
return orig.apply(this, [condition].concat(args.join('\n')));
};
})();
/**
* Wraps the function to use it as a callback, adding:
* - Stack trace of wrapping time, which better reveals the call site.
* - Bind this object
*
* @param {Object=} thisObject Object to be used as this.
* @param {...*} bindArgs Arguments to be bound with the wrapped function.
* @return {function(...)} Wrapped function.
*/
Function.prototype.wrap = function(thisObject, ...bindArgs) {
const func = this;
const bindStack = (new Error('Stack trace before async call')).stack;
if (thisObject === undefined) {
thisObject = null;
}
return function wrappedCallback(...args) {
try {
const finalArgs = bindArgs.concat(args);
return func.apply(thisObject, finalArgs);
} catch (e) {
// Log current exception and the stack for the binding time.
console.error(
e.stack || e,
'Exception happened in callback which was bound at:', bindStack);
throw e;
}
};
};
})();