diff --git a/packages/browser/src/tracekit.ts b/packages/browser/src/tracekit.ts index 28bd1d48006b..bd42165c65b6 100644 --- a/packages/browser/src/tracekit.ts +++ b/packages/browser/src/tracekit.ts @@ -50,13 +50,23 @@ const gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:file|https?|blob|chrome|webpac const winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i; const geckoEval = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i; const chromeEval = /\((\S*)(?::(\d+))(?::(\d+))\)/; +// Based on our own mapping pattern - https://github.com/getsentry/sentry/blob/9f08305e09866c8bd6d0c24f5b0aabdd7dd6c59c/src/sentry/lang/javascript/errormapping.py#L83-L108 +const reactMinifiedRegexp = /Minified React error #\d+;/i; /** JSDoc */ export function computeStackTrace(ex: any): StackTrace { // tslint:disable:no-unsafe-any let stack = null; - const popSize: number = ex && ex.framesToPop; + let popSize = 0; + + if (ex) { + if (typeof ex.framesToPop === 'number') { + popSize = ex.framesToPop; + } else if (reactMinifiedRegexp.test(ex.message)) { + popSize = 1; + } + } try { // This must be tried first because Opera 10 *destroys* diff --git a/packages/browser/test/unit/tracekit/custom.test.ts b/packages/browser/test/unit/tracekit/custom.test.ts index c210d7fca892..3a99a0218190 100644 --- a/packages/browser/test/unit/tracekit/custom.test.ts +++ b/packages/browser/test/unit/tracekit/custom.test.ts @@ -352,5 +352,98 @@ describe('Tracekit - Custom Tests', () => { }, ]); }); + + it('should correctly parse production errors and drop initial frame if its not relevant', () => { + const REACT_PRODUCTION_ERROR = { + message: + 'Minified React error #200; visit https://reactjs.org/docs/error-decoder.html?invariant=200 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.', + name: 'Error', + stack: `Error: Minified React error #200; visit https://reactjs.org/docs/error-decoder.html?invariant=200 for the full message or use the non-minified dev environment for full errors and additional helpful warnings. + at http://localhost:5000/static/js/foo.chunk.js:1:21738 + at a (http://localhost:5000/static/js/foo.chunk.js:1:21841) + at ho (http://localhost:5000/static/js/foo.chunk.js:1:68735) + at f (http://localhost:5000/:1:980)`, + }; + + const stacktrace = computeStackTrace(REACT_PRODUCTION_ERROR); + + expect(stacktrace.stack).deep.equal([ + { + args: [], + column: 21738, + func: '?', + line: 1, + url: 'http://localhost:5000/static/js/foo.chunk.js', + }, + { + args: [], + column: 21841, + func: 'a', + line: 1, + url: 'http://localhost:5000/static/js/foo.chunk.js', + }, + { + args: [], + column: 68735, + func: 'ho', + line: 1, + url: 'http://localhost:5000/static/js/foo.chunk.js', + }, + { + args: [], + column: 980, + func: 'f', + line: 1, + url: 'http://localhost:5000/', + }, + ]); + }); + + it('should not drop additional frame for production errors if framesToPop is still there', () => { + const REACT_PRODUCTION_ERROR = { + framesToPop: 1, + message: + 'Minified React error #200; visit https://reactjs.org/docs/error-decoder.html?invariant=200 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.', + name: 'Error', + stack: `Error: Minified React error #200; visit https://reactjs.org/docs/error-decoder.html?invariant=200 for the full message or use the non-minified dev environment for full errors and additional helpful warnings. + at http://localhost:5000/static/js/foo.chunk.js:1:21738 + at a (http://localhost:5000/static/js/foo.chunk.js:1:21841) + at ho (http://localhost:5000/static/js/foo.chunk.js:1:68735) + at f (http://localhost:5000/:1:980)`, + }; + + const stacktrace = computeStackTrace(REACT_PRODUCTION_ERROR); + + expect(stacktrace.stack).deep.equal([ + { + args: [], + column: 21738, + func: '?', + line: 1, + url: 'http://localhost:5000/static/js/foo.chunk.js', + }, + { + args: [], + column: 21841, + func: 'a', + line: 1, + url: 'http://localhost:5000/static/js/foo.chunk.js', + }, + { + args: [], + column: 68735, + func: 'ho', + line: 1, + url: 'http://localhost:5000/static/js/foo.chunk.js', + }, + { + args: [], + column: 980, + func: 'f', + line: 1, + url: 'http://localhost:5000/', + }, + ]); + }); }); });