diff --git a/package.json b/package.json index 36ea17ddc0e2..bd3787a51187 100644 --- a/package.json +++ b/package.json @@ -77,14 +77,17 @@ }, "lint-staged": { "src/**/*.js": [ + "eslint", "prettier --write", "git add" ], "test/**/*.js": [ + "eslint", "prettier --write", "git add" ], "plugins/**/*.js": [ + "eslint", "prettier --write", "git add" ] diff --git a/src/raven.js b/src/raven.js index bbbd6c1974be..e3475b02f106 100644 --- a/src/raven.js +++ b/src/raven.js @@ -222,6 +222,9 @@ Raven.prototype = { TraceKit.report.subscribe(function() { self._handleOnErrorStackInfo.apply(self, arguments); }); + + self._patchFunctionToString(); + if (self._globalOptions.instrument && self._globalOptions.instrument.tryCatch) { self._instrumentTryCatch(); } @@ -378,6 +381,7 @@ Raven.prototype = { uninstall: function() { TraceKit.report.uninstall(); + this._unpatchFunctionToString(); this._restoreBuiltIns(); Error.stackTraceLimit = this._originalErrorStackTraceLimit; @@ -940,6 +944,25 @@ Raven.prototype = { }); }, + _patchFunctionToString: function() { + var self = this; + self._originalFunctionToString = Function.prototype.toString; + // eslint-disable-next-line no-extend-native + Function.prototype.toString = function() { + if (typeof this === 'function' && this.__raven__) { + return self._originalFunctionToString.apply(this.__orig_method__, arguments); + } + return self._originalFunctionToString.apply(this, arguments); + }; + }, + + _unpatchFunctionToString: function() { + if (this._originalFunctionToString) { + // eslint-disable-next-line no-extend-native + Function.prototype.toString = this._originalFunctionToString; + } + }, + /** * Wrap timer functions and event targets to catch errors and provide * better metadata. diff --git a/src/utils.js b/src/utils.js index 7a4d59e0803f..90efbfcf449d 100644 --- a/src/utils.js +++ b/src/utils.js @@ -357,6 +357,8 @@ function isSameStacktrace(stack1, stack2) { function fill(obj, name, replacement, track) { var orig = obj[name]; obj[name] = replacement(orig); + obj[name].__raven__ = true; + obj[name].__orig_method__ = orig; if (track) { track.push([obj, name, orig]); } diff --git a/test/integration/test.js b/test/integration/test.js index b63e02bb52cf..a755dffeaa91 100644 --- a/test/integration/test.js +++ b/test/integration/test.js @@ -1254,6 +1254,46 @@ describe('integration', function() { } ); }); + + it('should preserve native code detection compatibility', function(done) { + var iframe = this.iframe; + + iframeExecute( + iframe, + done, + function() { + done(); + }, + function() { + assert.include( + Function.prototype.toString.call(window.setTimeout), + '[native code]' + ); + assert.include( + Function.prototype.toString.call(window.setInterval), + '[native code]' + ); + assert.include( + Function.prototype.toString.call(window.addEventListener), + '[native code]' + ); + assert.include( + Function.prototype.toString.call(window.removeEventListener), + '[native code]' + ); + assert.include( + Function.prototype.toString.call(window.requestAnimationFrame), + '[native code]' + ); + if ('fetch' in window) { + assert.include( + Function.prototype.toString.call(window.fetch), + '[native code]' + ); + } + } + ); + }); }); describe('uninstall', function() {