From 0ec6249baa49deafa4b18e8713aa98a48410c0b8 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Mon, 7 Feb 2022 23:16:23 +0000 Subject: [PATCH 1/5] Refactor tests and minor improvements --- packages/browser/src/tracekit.ts | 37 +- .../test/unit/tracekit/chromium.test.ts | 357 +++++++ .../browser/test/unit/tracekit/custom.test.ts | 623 ------------ .../test/unit/tracekit/firefox.test.ts | 270 +++++ .../browser/test/unit/tracekit/ie.test.ts | 83 ++ .../browser/test/unit/tracekit/misc.test.ts | 26 + .../browser/test/unit/tracekit/opera.test.ts | 142 +++ .../test/unit/tracekit/original.test.ts | 938 ------------------ .../test/unit/tracekit/originalfixtures.ts | 513 ---------- .../test/unit/tracekit/react-native.test.ts | 311 ++++++ .../browser/test/unit/tracekit/react.test.ts | 86 ++ .../browser/test/unit/tracekit/safari.test.ts | 294 ++++++ 12 files changed, 1577 insertions(+), 2103 deletions(-) create mode 100644 packages/browser/test/unit/tracekit/chromium.test.ts delete mode 100644 packages/browser/test/unit/tracekit/custom.test.ts create mode 100644 packages/browser/test/unit/tracekit/firefox.test.ts create mode 100644 packages/browser/test/unit/tracekit/ie.test.ts create mode 100644 packages/browser/test/unit/tracekit/misc.test.ts create mode 100644 packages/browser/test/unit/tracekit/opera.test.ts delete mode 100644 packages/browser/test/unit/tracekit/original.test.ts delete mode 100644 packages/browser/test/unit/tracekit/originalfixtures.ts create mode 100644 packages/browser/test/unit/tracekit/react-native.test.ts create mode 100644 packages/browser/test/unit/tracekit/react.test.ts create mode 100644 packages/browser/test/unit/tracekit/safari.test.ts diff --git a/packages/browser/src/tracekit.ts b/packages/browser/src/tracekit.ts index 1b163b3927e3..e91dc37ddc58 100644 --- a/packages/browser/src/tracekit.ts +++ b/packages/browser/src/tracekit.ts @@ -18,7 +18,6 @@ export interface StackFrame { url: string; func: string; - args: string[]; line: number | null; column: number | null; } @@ -43,7 +42,7 @@ const UNKNOWN_FUNCTION = '?'; // Chromium based browsers: Chrome, Brave, new Opera, new Edge const chrome = - /^\s*at (?:(.*?) ?\()?((?:file|https?|blob|chrome-extension|address|native|eval|webpack||[-a-z]+:|.*bundle|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i; + /^\s*at (?:(.*?) ?\((?:address at )?)?((?:file|https?|blob|chrome-extension|address|native|eval|webpack||[-a-z]+:|.*bundle|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i; // gecko regex: `(?:bundle|\d+\.js)`: `bundle` is for react native, `\d+\.js` also but specifically for ram bundles because it // generates filenames without a prefix like `file://` the filenames in the stacktrace are just 42.js // We need this specific case for now because we want no other regex to match. @@ -113,9 +112,8 @@ function computeStackTraceFromStackProp(ex: any): StackTrace | null { let parts; let element; - for (let i = 0; i < lines.length; ++i) { - if ((parts = chrome.exec(lines[i]))) { - const isNative = parts[2] && parts[2].indexOf('native') === 0; // start of line + for (const line of lines) { + if ((parts = chrome.exec(line))) { isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line if (isEval && (submatch = chromeEval.exec(parts[2]))) { // throw out eval line/column and use top-most line/column number @@ -124,30 +122,24 @@ function computeStackTraceFromStackProp(ex: any): StackTrace | null { parts[4] = submatch[3]; // column } - // Arpad: Working with the regexp above is super painful. it is quite a hack, but just stripping the `address at ` - // prefix here seems like the quickest solution for now. - let url = parts[2] && parts[2].indexOf('address at ') === 0 ? parts[2].substr('address at '.length) : parts[2]; // Kamil: One more hack won't hurt us right? Understanding and adding more rules on top of these regexps right now // would be way too time consuming. (TODO: Rewrite whole RegExp to be more readable) - let func = parts[1] || UNKNOWN_FUNCTION; - [func, url] = extractSafariExtensionDetails(func, url); + const [func, url] = extractSafariExtensionDetails(parts[1] || UNKNOWN_FUNCTION, parts[2]); element = { url, func, - args: isNative ? [parts[2]] : [], line: parts[3] ? +parts[3] : null, column: parts[4] ? +parts[4] : null, }; - } else if ((parts = winjs.exec(lines[i]))) { + } else if ((parts = winjs.exec(line))) { element = { url: parts[2], func: parts[1] || UNKNOWN_FUNCTION, - args: [], line: +parts[3], column: parts[4] ? +parts[4] : null, }; - } else if ((parts = gecko.exec(lines[i]))) { + } else if ((parts = gecko.exec(line))) { isEval = parts[3] && parts[3].indexOf(' > eval') > -1; if (isEval && (submatch = geckoEval.exec(parts[3]))) { // throw out eval line/column and use top-most line number @@ -155,12 +147,6 @@ function computeStackTraceFromStackProp(ex: any): StackTrace | null { parts[3] = submatch[1]; parts[4] = submatch[2]; parts[5] = ''; // no column when eval - } else if (i === 0 && !parts[5] && ex.columnNumber !== void 0) { - // FireFox uses this awesome columnNumber property for its top frame - // Also note, Firefox's column number is 0-based and everything else expects 1-based, - // so adding 1 - // NOTE: this hack doesn't work if top-most frame is eval - stack[0].column = (ex.columnNumber as number) + 1; } let url = parts[3]; @@ -170,7 +156,6 @@ function computeStackTraceFromStackProp(ex: any): StackTrace | null { element = { url, func, - args: parts[2] ? parts[2].split(',') : [], line: parts[4] ? +parts[4] : null, column: parts[5] ? +parts[5] : null, }; @@ -178,10 +163,6 @@ function computeStackTraceFromStackProp(ex: any): StackTrace | null { continue; } - if (!element.func && element.line) { - element.func = UNKNOWN_FUNCTION; - } - stack.push(element); } @@ -208,7 +189,7 @@ function computeStackTraceFromStacktraceProp(ex: any): StackTrace | null { const stacktrace = ex.stacktrace; const opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i; const opera11Regex = - / line (\d+), column (\d+)\s*(?:in (?:]+)>|([^)]+))\((.*)\))? in (.*):\s*$/i; + / line (\d+), column (\d+)\s*(?:in (?:]+)>|([^)]+))\(.*\))? in (.*):\s*$/i; const lines = stacktrace.split('\n'); const stack = []; let parts; @@ -219,15 +200,13 @@ function computeStackTraceFromStacktraceProp(ex: any): StackTrace | null { element = { url: parts[2], func: parts[3], - args: [], line: +parts[1], column: null, }; } else if ((parts = opera11Regex.exec(lines[line]))) { element = { - url: parts[6], + url: parts[5], func: parts[3] || parts[4], - args: parts[5] ? parts[5].split(',') : [], line: +parts[1], column: +parts[2], }; diff --git a/packages/browser/test/unit/tracekit/chromium.test.ts b/packages/browser/test/unit/tracekit/chromium.test.ts new file mode 100644 index 000000000000..65555c4656b6 --- /dev/null +++ b/packages/browser/test/unit/tracekit/chromium.test.ts @@ -0,0 +1,357 @@ +import { computeStackTrace } from '../../../src/tracekit'; + +describe('Tracekit - Chrome Tests', () => { + it('should parse Chrome error with no location', () => { + const NO_LOCATION = { message: 'foo', name: 'bar', stack: 'error\n at Array.forEach (native)' }; + const stackFrames = computeStackTrace(NO_LOCATION); + + expect(stackFrames).toEqual({ + message: 'foo', + name: 'bar', + stack: [{ url: 'native', func: 'Array.forEach', line: null, column: null }], + }); + }); + + it('should parse Chrome 15 error', () => { + const CHROME_15 = { + name: 'foo', + arguments: ['undef'], + message: "Object # has no method 'undef'", + stack: + "TypeError: Object # has no method 'undef'\n" + + ' at bar (http://path/to/file.js:13:17)\n' + + ' at bar (http://path/to/file.js:16:5)\n' + + ' at foo (http://path/to/file.js:20:5)\n' + + ' at http://path/to/file.js:24:4', + }; + + const stackFrames = computeStackTrace(CHROME_15); + + expect(stackFrames).toEqual({ + message: "Object # has no method 'undef'", + name: 'foo', + stack: [ + { url: 'http://path/to/file.js', func: 'bar', line: 13, column: 17 }, + { url: 'http://path/to/file.js', func: 'bar', line: 16, column: 5 }, + { url: 'http://path/to/file.js', func: 'foo', line: 20, column: 5 }, + { url: 'http://path/to/file.js', func: '?', line: 24, column: 4 }, + ], + }); + }); + + it('should parse Chrome 36 error with port numbers', () => { + const CHROME_36 = { + message: 'Default error', + name: 'Error', + stack: + 'Error: Default error\n' + + ' at dumpExceptionError (http://localhost:8080/file.js:41:27)\n' + + ' at HTMLButtonElement.onclick (http://localhost:8080/file.js:107:146)\n' + + ' at I.e.fn.(anonymous function) [as index] (http://localhost:8080/file.js:10:3651)', + }; + + const stackFrames = computeStackTrace(CHROME_36); + + expect(stackFrames).toEqual({ + message: 'Default error', + name: 'Error', + stack: [ + { url: 'http://localhost:8080/file.js', func: 'dumpExceptionError', line: 41, column: 27 }, + { url: 'http://localhost:8080/file.js', func: 'HTMLButtonElement.onclick', line: 107, column: 146 }, + { + url: 'http://localhost:8080/file.js', + func: 'I.e.fn.(anonymous function) [as index]', + line: 10, + column: 3651, + }, + ], + }); + }); + + it('should parse Chrome error with webpack URLs', () => { + // can be generated when Webpack is built with { devtool: eval } + const CHROME_XX_WEBPACK = { + message: "Cannot read property 'error' of undefined", + name: 'TypeError', + stack: + "TypeError: Cannot read property 'error' of undefined\n" + + ' at TESTTESTTEST.eval(webpack:///./src/components/test/test.jsx?:295:108)\n' + + ' at TESTTESTTEST.render(webpack:///./src/components/test/test.jsx?:272:32)\n' + + ' at TESTTESTTEST.tryRender(webpack:///./~/react-transform-catch-errors/lib/index.js?:34:31)\n' + + ' at TESTTESTTEST.proxiedMethod(webpack:///./~/react-proxy/modules/createPrototypeProxy.js?:44:30)', + }; + + const stackFrames = computeStackTrace(CHROME_XX_WEBPACK); + + expect(stackFrames).toEqual({ + message: "Cannot read property 'error' of undefined", + name: 'TypeError', + stack: [ + { url: 'webpack:///./src/components/test/test.jsx?', func: 'TESTTESTTEST.eval', line: 295, column: 108 }, + { url: 'webpack:///./src/components/test/test.jsx?', func: 'TESTTESTTEST.render', line: 272, column: 32 }, + { + url: 'webpack:///./~/react-transform-catch-errors/lib/index.js?', + func: 'TESTTESTTEST.tryRender', + line: 34, + column: 31, + }, + { + url: 'webpack:///./~/react-proxy/modules/createPrototypeProxy.js?', + func: 'TESTTESTTEST.proxiedMethod', + line: 44, + column: 30, + }, + ], + }); + }); + + it('should parse nested eval() from Chrome', () => { + const CHROME_48_EVAL = { + message: 'message string', + name: 'Error', + stack: + 'Error: message string\n' + + 'at baz (eval at foo (eval at speak (http://localhost:8080/file.js:21:17)), :1:30)\n' + + 'at foo (eval at speak (http://localhost:8080/file.js:21:17), :2:96)\n' + + 'at eval (eval at speak (http://localhost:8080/file.js:21:17), :4:18)\n' + + 'at Object.speak (http://localhost:8080/file.js:21:17)\n' + + 'at http://localhost:8080/file.js:31:13\n', + }; + + const stackFrames = computeStackTrace(CHROME_48_EVAL); + + expect(stackFrames).toEqual({ + message: 'message string', + name: 'Error', + stack: [ + { url: 'http://localhost:8080/file.js', func: 'baz', line: 21, column: 17 }, + { url: 'http://localhost:8080/file.js', func: 'foo', line: 21, column: 17 }, + { url: 'http://localhost:8080/file.js', func: 'eval', line: 21, column: 17 }, + { url: 'http://localhost:8080/file.js', func: 'Object.speak', line: 21, column: 17 }, + { url: 'http://localhost:8080/file.js', func: '?', line: 31, column: 13 }, + ], + }); + }); + + it('should parse Chrome error with blob URLs', () => { + const CHROME_48_BLOB = { + message: 'Error: test', + name: 'Error', + stack: + 'Error: test\n' + + ' at Error (native)\n' + + ' at s (blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379:31:29146)\n' + + ' at Object.d [as add] (blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379:31:30039)\n' + + ' at blob:http%3A//localhost%3A8080/d4eefe0f-361a-4682-b217-76587d9f712a:15:10978\n' + + ' at blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379:1:6911\n' + + ' at n.fire (blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379:7:3019)\n' + + ' at n.handle (blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379:7:2863)', + }; + + const stackFrames = computeStackTrace(CHROME_48_BLOB); + + expect(stackFrames).toEqual({ + message: 'Error: test', + name: 'Error', + stack: [ + { url: 'native', func: 'Error', line: null, column: null }, + { + url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', + func: 's', + line: 31, + column: 29146, + }, + { + url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', + func: 'Object.d [as add]', + line: 31, + column: 30039, + }, + { + url: 'blob:http%3A//localhost%3A8080/d4eefe0f-361a-4682-b217-76587d9f712a', + func: '?', + line: 15, + column: 10978, + }, + { + url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', + func: '?', + line: 1, + column: 6911, + }, + { + url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', + func: 'n.fire', + line: 7, + column: 3019, + }, + { + url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', + func: 'n.handle', + line: 7, + column: 2863, + }, + ], + }); + }); + + it('should parse errors with custom schemes', () => { + const CHROMIUM_EMBEDDED_FRAMEWORK_CUSTOM_SCHEME = { + message: 'message string', + name: 'Error', + stack: `Error: message string + at examplescheme://examplehost/cd351f7250857e22ceaa.worker.js:70179:15`, + }; + + const stacktrace = computeStackTrace(CHROMIUM_EMBEDDED_FRAMEWORK_CUSTOM_SCHEME); + + expect(stacktrace).toEqual({ + message: 'message string', + name: 'Error', + stack: [ + { url: 'examplescheme://examplehost/cd351f7250857e22ceaa.worker.js', func: '?', line: 70179, column: 15 }, + ], + }); + }); + + it('should parse Chrome 73 with native code frames', () => { + const CHROME73_NATIVE_CODE_EXCEPTION = { + message: 'test', + name: 'Error', + stack: `Error: test + at fooIterator (http://localhost:5000/test:20:17) + at Array.map () + at foo (http://localhost:5000/test:19:19) + at http://localhost:5000/test:24:7`, + }; + + const stacktrace = computeStackTrace(CHROME73_NATIVE_CODE_EXCEPTION); + + expect(stacktrace).toEqual({ + message: 'test', + name: 'Error', + stack: [ + { url: 'http://localhost:5000/test', func: 'fooIterator', line: 20, column: 17 }, + { url: '', func: 'Array.map', line: null, column: null }, + { url: 'http://localhost:5000/test', func: 'foo', line: 19, column: 19 }, + { url: 'http://localhost:5000/test', func: '?', line: 24, column: 7 }, + ], + }); + }); + + it('should parse exceptions with eval frames in Chrome 73', () => { + const CHROME73_EVAL_EXCEPTION = { + message: 'bad', + name: 'Error', + stack: `Error: bad + at Object.aha (http://localhost:5000/:19:13) + at callAnotherThing (http://localhost:5000/:20:16) + at Object.callback (http://localhost:5000/:25:7) + at http://localhost:5000/:34:17 + at Array.map () + at test (http://localhost:5000/:33:23) + at eval (eval at aha (http://localhost:5000/:37:5), :1:1) + at aha (http://localhost:5000/:39:5) + at Foo.testMethod (http://localhost:5000/:44:7) + at http://localhost:5000/:50:19`, + }; + + const stacktrace = computeStackTrace(CHROME73_EVAL_EXCEPTION); + + expect(stacktrace).toEqual({ + message: 'bad', + name: 'Error', + stack: [ + { url: 'http://localhost:5000/', func: 'Object.aha', line: 19, column: 13 }, + { url: 'http://localhost:5000/', func: 'callAnotherThing', line: 20, column: 16 }, + { url: 'http://localhost:5000/', func: 'Object.callback', line: 25, column: 7 }, + { url: 'http://localhost:5000/', func: '?', line: 34, column: 17 }, + { url: '', func: 'Array.map', line: null, column: null }, + { url: 'http://localhost:5000/', func: 'test', line: 33, column: 23 }, + { url: 'http://localhost:5000/', func: 'eval', line: 37, column: 5 }, + { url: 'http://localhost:5000/', func: 'aha', line: 39, column: 5 }, + { url: 'http://localhost:5000/', func: 'Foo.testMethod', line: 44, column: 7 }, + { url: 'http://localhost:5000/', func: '?', line: 50, column: 19 }, + ], + }); + }); + + it('should parse exceptions with native code frames in Edge 44', () => { + const EDGE44_NATIVE_CODE_EXCEPTION = { + message: 'test', + name: 'Error', + stack: `Error: test + at fooIterator (http://localhost:5000/test:20:11) + at Array.prototype.map (native code) + at foo (http://localhost:5000/test:19:9) + at Global code (http://localhost:5000/test:24:7)`, + }; + + const stacktrace = computeStackTrace(EDGE44_NATIVE_CODE_EXCEPTION); + + expect(stacktrace).toEqual({ + message: 'test', + name: 'Error', + stack: [ + { url: 'http://localhost:5000/test', func: 'fooIterator', line: 20, column: 11 }, + { url: 'native code', func: 'Array.prototype.map', line: null, column: null }, + { url: 'http://localhost:5000/test', func: 'foo', line: 19, column: 9 }, + { url: 'http://localhost:5000/test', func: 'Global code', line: 24, column: 7 }, + ], + }); + }); + + it('should parse exceptions with eval frames in Edge 44', () => { + const EDGE44_EVAL_EXCEPTION = { + message: 'aha', + name: 'Error', + stack: `Error: bad + at aha (http://localhost:5000/:19:7) + at callAnotherThing (http://localhost:5000/:18:6) + at callback (http://localhost:5000/:25:7) + at Anonymous function (http://localhost:5000/:34:7) + at Array.prototype.map (native code) + at test (http://localhost:5000/:33:5) + at eval code (eval code:1:1) + at aha (http://localhost:5000/:39:5) + at Foo.prototype.testMethod (http://localhost:5000/:44:7) + at Anonymous function (http://localhost:5000/:50:8)`, + }; + + const stacktrace = computeStackTrace(EDGE44_EVAL_EXCEPTION); + + expect(stacktrace).toEqual({ + message: 'aha', + name: 'Error', + stack: [ + { url: 'http://localhost:5000/', func: 'aha', line: 19, column: 7 }, + { url: 'http://localhost:5000/', func: 'callAnotherThing', line: 18, column: 6 }, + { url: 'http://localhost:5000/', func: 'callback', line: 25, column: 7 }, + { url: 'http://localhost:5000/', func: 'Anonymous function', line: 34, column: 7 }, + { url: 'native code', func: 'Array.prototype.map', line: null, column: null }, + { url: 'http://localhost:5000/', func: 'test', line: 33, column: 5 }, + { url: 'eval code', func: 'eval code', line: 1, column: 1 }, + { url: 'http://localhost:5000/', func: 'aha', line: 39, column: 5 }, + { url: 'http://localhost:5000/', func: 'Foo.prototype.testMethod', line: 44, column: 7 }, + { url: 'http://localhost:5000/', func: 'Anonymous function', line: 50, column: 8 }, + ], + }); + }); + + it('should parse exceptions called within an iframe in Electron Renderer', () => { + const CHROME_ELECTRON_RENDERER = { + message: "Cannot read property 'error' of undefined", + name: 'TypeError', + stack: `TypeError: Cannot read property 'error' of undefined + at TESTTESTTEST.someMethod (C:\\Users\\user\\path\\to\\file.js:295:108)`, + }; + + const stacktrace = computeStackTrace(CHROME_ELECTRON_RENDERER); + + expect(stacktrace).toEqual({ + message: "Cannot read property 'error' of undefined", + name: 'TypeError', + stack: [{ url: 'C:\\Users\\user\\path\\to\\file.js', func: 'TESTTESTTEST.someMethod', line: 295, column: 108 }], + }); + }); +}); diff --git a/packages/browser/test/unit/tracekit/custom.test.ts b/packages/browser/test/unit/tracekit/custom.test.ts deleted file mode 100644 index 44c0ca490239..000000000000 --- a/packages/browser/test/unit/tracekit/custom.test.ts +++ /dev/null @@ -1,623 +0,0 @@ -import { computeStackTrace } from '../../../src/tracekit'; - -describe('Tracekit - Custom Tests', () => { - it('should parse errors with custom schemes', () => { - const CHROMIUM_EMBEDDED_FRAMEWORK_CUSTOM_SCHEME = { - message: 'message string', - name: 'Error', - stack: `Error: message string - at examplescheme://examplehost/cd351f7250857e22ceaa.worker.js:70179:15`, - }; - - const stacktrace = computeStackTrace(CHROMIUM_EMBEDDED_FRAMEWORK_CUSTOM_SCHEME); - - expect(stacktrace.stack).toEqual([ - { - args: [], - column: 15, - func: '?', - line: 70179, - url: 'examplescheme://examplehost/cd351f7250857e22ceaa.worker.js', - }, - ]); - }); - - describe('Safari extensions', () => { - it('should parse exceptions for safari-extension', () => { - const SAFARI_EXTENSION_EXCEPTION = { - message: 'wat', - name: 'Error', - stack: `Error: wat - at ClipperError@safari-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js:223036:10) - at safari-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js:3313:26)`, - }; - const stacktrace = computeStackTrace(SAFARI_EXTENSION_EXCEPTION); - expect(stacktrace.stack).toEqual([ - { - url: 'safari-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js', - func: 'ClipperError', - args: [], - line: 223036, - column: 10, - }, - { - url: 'safari-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js', - func: '?', - args: [], - line: 3313, - column: 26, - }, - ]); - }); - - it('should parse exceptions for safari-extension with frames-only stack', () => { - const SAFARI_EXTENSION_EXCEPTION = { - message: `undefined is not an object (evaluating 'e.groups.includes')`, - name: `TypeError`, - stack: `isClaimed@safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js:2:929865 - safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js:2:1588410 - promiseReactionJob@[native code]`, - }; - const stacktrace = computeStackTrace(SAFARI_EXTENSION_EXCEPTION); - - expect(stacktrace.stack).toEqual([ - { - url: 'safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js', - func: 'isClaimed', - args: [], - line: 2, - column: 929865, - }, - { - url: 'safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js', - func: '?', - args: [], - line: 2, - column: 1588410, - }, - { - url: '[native code]', - func: 'promiseReactionJob', - args: [], - line: null, - column: null, - }, - ]); - }); - - it('should parse exceptions for safari-web-extension', () => { - const SAFARI_WEB_EXTENSION_EXCEPTION = { - message: 'wat', - name: 'Error', - stack: `Error: wat - at ClipperError@safari-web-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js:223036:10) - at safari-web-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js:3313:26)`, - }; - const stacktrace = computeStackTrace(SAFARI_WEB_EXTENSION_EXCEPTION); - expect(stacktrace.stack).toEqual([ - { - url: 'safari-web-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js', - func: 'ClipperError', - args: [], - line: 223036, - column: 10, - }, - { - url: 'safari-web-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js', - func: '?', - args: [], - line: 3313, - column: 26, - }, - ]); - }); - - it('should parse exceptions for safari-web-extension with frames-only stack', () => { - const SAFARI_EXTENSION_EXCEPTION = { - message: `undefined is not an object (evaluating 'e.groups.includes')`, - name: `TypeError`, - stack: `p_@safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js:29:33314 - safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js:29:56027 - promiseReactionJob@[native code]`, - }; - const stacktrace = computeStackTrace(SAFARI_EXTENSION_EXCEPTION); - - expect(stacktrace.stack).toEqual([ - { - url: 'safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js', - func: 'p_', - args: [], - line: 29, - column: 33314, - }, - { - url: 'safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js', - func: '?', - args: [], - line: 29, - column: 56027, - }, - { - url: '[native code]', - func: 'promiseReactionJob', - args: [], - line: null, - column: null, - }, - ]); - }); - }); - - it('should parse exceptions for react-native-v8', () => { - const REACT_NATIVE_V8_EXCEPTION = { - message: 'Manually triggered crash to test Sentry reporting', - name: 'Error', - stack: `Error: Manually triggered crash to test Sentry reporting - at Object.onPress(index.android.bundle:2342:3773) - at s.touchableHandlePress(index.android.bundle:214:2048) - at s._performSideEffectsForTransition(index.android.bundle:198:9608) - at s._receiveSignal(index.android.bundle:198:8309) - at s.touchableHandleResponderRelease(index.android.bundle:198:5615) - at Object.y(index.android.bundle:93:571) - at P(index.android.bundle:93:714)`, - }; - const stacktrace = computeStackTrace(REACT_NATIVE_V8_EXCEPTION); - expect(stacktrace.stack).toEqual([ - { url: 'index.android.bundle', func: 'Object.onPress', args: [], line: 2342, column: 3773 }, - { url: 'index.android.bundle', func: 's.touchableHandlePress', args: [], line: 214, column: 2048 }, - { url: 'index.android.bundle', func: 's._performSideEffectsForTransition', args: [], line: 198, column: 9608 }, - { url: 'index.android.bundle', func: 's._receiveSignal', args: [], line: 198, column: 8309 }, - { url: 'index.android.bundle', func: 's.touchableHandleResponderRelease', args: [], line: 198, column: 5615 }, - { url: 'index.android.bundle', func: 'Object.y', args: [], line: 93, column: 571 }, - { url: 'index.android.bundle', func: 'P', args: [], line: 93, column: 714 }, - ]); - }); - - it('should parse exceptions for react-native Expo bundles', () => { - const REACT_NATIVE_EXPO_EXCEPTION = { - message: 'Test Error Expo', - name: 'Error', - stack: `onPress@/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3:595:658 - value@/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3:221:7656 - onResponderRelease@/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3:221:5666 - p@/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3:96:385 - forEach@[native code]`, - }; - const stacktrace = computeStackTrace(REACT_NATIVE_EXPO_EXCEPTION); - expect(stacktrace.stack).toEqual([ - { - url: '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', - func: 'onPress', - args: [], - line: 595, - column: 658, - }, - { - url: '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', - func: 'value', - args: [], - line: 221, - column: 7656, - }, - { - url: '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', - func: 'onResponderRelease', - args: [], - line: 221, - column: 5666, - }, - { - url: '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', - func: 'p', - args: [], - line: 96, - column: 385, - }, - { - url: '[native code]', - func: 'forEach', - args: [], - line: null, - column: null, - }, - ]); - }); - - describe('should parse exceptions with native code frames', () => { - it('in Chrome 73', () => { - const CHROME73_NATIVE_CODE_EXCEPTION = { - message: 'test', - name: 'Error', - stack: `Error: test - at fooIterator (http://localhost:5000/test:20:17) - at Array.map () - at foo (http://localhost:5000/test:19:19) - at http://localhost:5000/test:24:7`, - }; - - const stacktrace = computeStackTrace(CHROME73_NATIVE_CODE_EXCEPTION); - - expect(stacktrace.stack).toEqual([ - { args: [], column: 17, func: 'fooIterator', line: 20, url: 'http://localhost:5000/test' }, - { args: [], column: null, func: 'Array.map', line: null, url: '' }, - { args: [], column: 19, func: 'foo', line: 19, url: 'http://localhost:5000/test' }, - { args: [], column: 7, func: '?', line: 24, url: 'http://localhost:5000/test' }, - ]); - }); - - it('in Firefox 66', () => { - const FIREFOX66_NATIVE_CODE_EXCEPTION = { - message: 'test', - name: 'Error', - stack: `fooIterator@http://localhost:5000/test:20:17 - foo@http://localhost:5000/test:19:19 - @http://localhost:5000/test:24:7`, - }; - - const stacktrace = computeStackTrace(FIREFOX66_NATIVE_CODE_EXCEPTION); - - expect(stacktrace.stack).toEqual([ - { args: [], column: 17, func: 'fooIterator', line: 20, url: 'http://localhost:5000/test' }, - { args: [], column: 19, func: 'foo', line: 19, url: 'http://localhost:5000/test' }, - { args: [], column: 7, func: '?', line: 24, url: 'http://localhost:5000/test' }, - ]); - }); - - it('in Safari 12', () => { - const SAFARI12_NATIVE_CODE_EXCEPTION = { - message: 'test', - name: 'Error', - stack: `fooIterator@http://localhost:5000/test:20:26 - map@[native code] - foo@http://localhost:5000/test:19:22 - global code@http://localhost:5000/test:24:10`, - }; - - const stacktrace = computeStackTrace(SAFARI12_NATIVE_CODE_EXCEPTION); - - expect(stacktrace.stack).toEqual([ - { args: [], column: 26, func: 'fooIterator', line: 20, url: 'http://localhost:5000/test' }, - { args: [], column: null, func: 'map', line: null, url: '[native code]' }, - { args: [], column: 22, func: 'foo', line: 19, url: 'http://localhost:5000/test' }, - { args: [], column: 10, func: 'global code', line: 24, url: 'http://localhost:5000/test' }, - ]); - }); - - it('in Edge 44', () => { - const EDGE44_NATIVE_CODE_EXCEPTION = { - message: 'test', - name: 'Error', - stack: `Error: test - at fooIterator (http://localhost:5000/test:20:11) - at Array.prototype.map (native code) - at foo (http://localhost:5000/test:19:9) - at Global code (http://localhost:5000/test:24:7)`, - }; - - const stacktrace = computeStackTrace(EDGE44_NATIVE_CODE_EXCEPTION); - - expect(stacktrace.stack).toEqual([ - { args: [], column: 11, func: 'fooIterator', line: 20, url: 'http://localhost:5000/test' }, - { - args: ['native code'], - column: null, - func: 'Array.prototype.map', - line: null, - url: 'native code', - }, - { args: [], column: 9, func: 'foo', line: 19, url: 'http://localhost:5000/test' }, - { args: [], column: 7, func: 'Global code', line: 24, url: 'http://localhost:5000/test' }, - ]); - }); - }); - - describe('should parse exceptions with eval frames', () => { - it('in Chrome 73', () => { - const CHROME73_EVAL_EXCEPTION = { - message: 'bad', - name: 'Error', - stack: `Error: bad - at Object.aha (http://localhost:5000/:19:13) - at callAnotherThing (http://localhost:5000/:20:16) - at Object.callback (http://localhost:5000/:25:7) - at http://localhost:5000/:34:17 - at Array.map () - at test (http://localhost:5000/:33:23) - at eval (eval at aha (http://localhost:5000/:37:5), :1:1) - at aha (http://localhost:5000/:39:5) - at Foo.testMethod (http://localhost:5000/:44:7) - at http://localhost:5000/:50:19`, - }; - - const stacktrace = computeStackTrace(CHROME73_EVAL_EXCEPTION); - - expect(stacktrace.stack).toEqual([ - { column: 13, url: 'http://localhost:5000/', func: 'Object.aha', line: 19, args: [] }, - { column: 16, url: 'http://localhost:5000/', func: 'callAnotherThing', line: 20, args: [] }, - { column: 7, url: 'http://localhost:5000/', func: 'Object.callback', line: 25, args: [] }, - { column: 17, url: 'http://localhost:5000/', func: '?', line: 34, args: [] }, - { column: null, url: '', func: 'Array.map', line: null, args: [] }, - { column: 23, url: 'http://localhost:5000/', func: 'test', line: 33, args: [] }, - { column: 5, url: 'http://localhost:5000/', func: 'eval', line: 37, args: [] }, - { column: 5, url: 'http://localhost:5000/', func: 'aha', line: 39, args: [] }, - { column: 7, url: 'http://localhost:5000/', func: 'Foo.testMethod', line: 44, args: [] }, - { column: 19, url: 'http://localhost:5000/', func: '?', line: 50, args: [] }, - ]); - }); - - it('in Firefox 66', () => { - const FIREFOX66_EVAL_EXCEPTION = { - message: 'aha', - name: 'Error', - stack: `aha@http://localhost:5000/:19:13 - callAnotherThing@http://localhost:5000/:20:15 - callback@http://localhost:5000/:25:7 - test/<@http://localhost:5000/:34:7 - test@http://localhost:5000/:33:23 - @http://localhost:5000/ line 39 > eval:1:1 - aha@http://localhost:5000/:39:5 - testMethod@http://localhost:5000/:44:7 - @http://localhost:5000/:50:19`, - }; - - const stacktrace = computeStackTrace(FIREFOX66_EVAL_EXCEPTION); - - expect(stacktrace.stack).toEqual([ - { column: 13, url: 'http://localhost:5000/', func: 'aha', line: 19, args: [] }, - { column: 15, url: 'http://localhost:5000/', func: 'callAnotherThing', line: 20, args: [] }, - { column: 7, url: 'http://localhost:5000/', func: 'callback', line: 25, args: [] }, - { column: 7, url: 'http://localhost:5000/', func: 'test/<', line: 34, args: [] }, - { column: 23, url: 'http://localhost:5000/', func: 'test', line: 33, args: [] }, - { column: null, url: 'http://localhost:5000/', func: 'eval', line: 39, args: [] }, - { column: 5, url: 'http://localhost:5000/', func: 'aha', line: 39, args: [] }, - { column: 7, url: 'http://localhost:5000/', func: 'testMethod', line: 44, args: [] }, - { column: 19, url: 'http://localhost:5000/', func: '?', line: 50, args: [] }, - ]); - }); - - it('in Safari 12', () => { - const SAFARI12_EVAL_EXCEPTION = { - message: 'aha', - name: 'Error', - stack: `aha@http://localhost:5000/:19:22 - aha@[native code] - callAnotherThing@http://localhost:5000/:20:16 - callback@http://localhost:5000/:25:23 - http://localhost:5000/:34:25 - map@[native code] - test@http://localhost:5000/:33:26 - eval code - eval@[native code] - aha@http://localhost:5000/:39:9 - testMethod@http://localhost:5000/:44:10 - http://localhost:5000/:50:29`, - }; - - const stacktrace = computeStackTrace(SAFARI12_EVAL_EXCEPTION); - - expect(stacktrace.stack).toEqual([ - { column: 22, url: 'http://localhost:5000/', func: 'aha', line: 19, args: [] }, - { column: null, url: '[native code]', func: 'aha', line: null, args: [] }, - { column: 16, url: 'http://localhost:5000/', func: 'callAnotherThing', line: 20, args: [] }, - { column: 23, url: 'http://localhost:5000/', func: 'callback', line: 25, args: [] }, - { column: 25, url: 'http://localhost:5000/', func: '?', line: 34, args: [] }, - { column: null, url: '[native code]', func: 'map', line: null, args: [] }, - { column: 26, url: 'http://localhost:5000/', func: 'test', line: 33, args: [] }, - { column: null, url: '[native code]', func: 'eval', line: null, args: [] }, - { column: 9, url: 'http://localhost:5000/', func: 'aha', line: 39, args: [] }, - { column: 10, url: 'http://localhost:5000/', func: 'testMethod', line: 44, args: [] }, - { column: 29, url: 'http://localhost:5000/', func: '?', line: 50, args: [] }, - ]); - }); - - it('in Edge 44', () => { - const EDGE44_EVAL_EXCEPTION = { - message: 'aha', - name: 'Error', - stack: `Error: bad - at aha (http://localhost:5000/:19:7) - at callAnotherThing (http://localhost:5000/:18:6) - at callback (http://localhost:5000/:25:7) - at Anonymous function (http://localhost:5000/:34:7) - at Array.prototype.map (native code) - at test (http://localhost:5000/:33:5) - at eval code (eval code:1:1) - at aha (http://localhost:5000/:39:5) - at Foo.prototype.testMethod (http://localhost:5000/:44:7) - at Anonymous function (http://localhost:5000/:50:8)`, - }; - - const stacktrace = computeStackTrace(EDGE44_EVAL_EXCEPTION); - - expect(stacktrace.stack).toEqual([ - { column: 7, url: 'http://localhost:5000/', func: 'aha', line: 19, args: [] }, - { column: 6, url: 'http://localhost:5000/', func: 'callAnotherThing', line: 18, args: [] }, - { column: 7, url: 'http://localhost:5000/', func: 'callback', line: 25, args: [] }, - { column: 7, url: 'http://localhost:5000/', func: 'Anonymous function', line: 34, args: [] }, - { - args: ['native code'], - column: null, - func: 'Array.prototype.map', - line: null, - url: 'native code', - }, - { column: 5, url: 'http://localhost:5000/', func: 'test', line: 33, args: [] }, - { column: 1, url: 'eval code', func: 'eval code', line: 1, args: [] }, - { column: 5, url: 'http://localhost:5000/', func: 'aha', line: 39, args: [] }, - { - args: [], - column: 7, - func: 'Foo.prototype.testMethod', - line: 44, - url: 'http://localhost:5000/', - }, - { column: 8, url: 'http://localhost:5000/', func: 'Anonymous function', line: 50, args: [] }, - ]); - }); - }); - - describe('should parse exceptions called within an iframe', () => { - it('in Electron Renderer', () => { - const CHROME_ELECTRON_RENDERER = { - message: "Cannot read property 'error' of undefined", - name: 'TypeError', - stack: `TypeError: Cannot read property 'error' of undefined - at TESTTESTTEST.someMethod (C:\\Users\\user\\path\\to\\file.js:295:108)`, - }; - - const stacktrace = computeStackTrace(CHROME_ELECTRON_RENDERER); - - expect(stacktrace.stack).toEqual([ - { - args: [], - column: 108, - func: 'TESTTESTTEST.someMethod', - line: 295, - url: 'C:\\Users\\user\\path\\to\\file.js', - }, - ]); - }); - }); - - describe('React', () => { - it('should correctly parse Invariant Violation errors and use framesToPop to drop info message', () => { - const REACT_INVARIANT_VIOLATION_EXCEPTION = { - framesToPop: 1, - message: - 'Minified React error #31; visit https://reactjs.org/docs/error-decoder.html?invariant=31&args[]=object%20with%20keys%20%7B%7D&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings. ', - name: 'Invariant Violation', - stack: `Invariant Violation: Minified React error #31; visit https://reactjs.org/docs/error-decoder.html?invariant=31&args[]=object%20with%20keys%20%7B%7D&args[]= 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_INVARIANT_VIOLATION_EXCEPTION); - - expect(stacktrace.stack).toEqual([ - { - 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 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).toEqual([ - { - 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).toEqual([ - { - 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/', - }, - ]); - }); - }); -}); diff --git a/packages/browser/test/unit/tracekit/firefox.test.ts b/packages/browser/test/unit/tracekit/firefox.test.ts new file mode 100644 index 000000000000..03414c66da3a --- /dev/null +++ b/packages/browser/test/unit/tracekit/firefox.test.ts @@ -0,0 +1,270 @@ +import { computeStackTrace } from '../../../src/tracekit'; + +describe('Tracekit - Firefox Tests', () => { + it('should parse Firefox 3 error', () => { + const FIREFOX_3 = { + fileName: 'http://127.0.0.1:8000/js/stacktrace.js', + lineNumber: 44, + message: 'this.undef is not a function', + name: 'TypeError', + stack: + '()@http://127.0.0.1:8000/js/stacktrace.js:44\n' + + '(null)@http://127.0.0.1:8000/js/stacktrace.js:31\n' + + 'printStackTrace()@http://127.0.0.1:8000/js/stacktrace.js:18\n' + + 'bar(1)@http://127.0.0.1:8000/js/file.js:13\n' + + 'bar(2)@http://127.0.0.1:8000/js/file.js:16\n' + + 'foo()@http://127.0.0.1:8000/js/file.js:20\n' + + '@http://127.0.0.1:8000/js/file.js:24\n' + + '', + }; + + const stackFrames = computeStackTrace(FIREFOX_3); + + expect(stackFrames).toEqual({ + message: 'this.undef is not a function', + name: 'TypeError', + stack: [ + { url: 'http://127.0.0.1:8000/js/stacktrace.js', func: '?', line: 44, column: null }, + { url: 'http://127.0.0.1:8000/js/stacktrace.js', func: '?', line: 31, column: null }, + { url: 'http://127.0.0.1:8000/js/stacktrace.js', func: 'printStackTrace', line: 18, column: null }, + { url: 'http://127.0.0.1:8000/js/file.js', func: 'bar', line: 13, column: null }, + { url: 'http://127.0.0.1:8000/js/file.js', func: 'bar', line: 16, column: null }, + { url: 'http://127.0.0.1:8000/js/file.js', func: 'foo', line: 20, column: null }, + { url: 'http://127.0.0.1:8000/js/file.js', func: '?', line: 24, column: null }, + ], + }); + }); + + it('should parse Firefox 7 error', () => { + const FIREFOX_7 = { + name: 'foo', + message: 'bar', + fileName: 'file:///G:/js/stacktrace.js', + lineNumber: 44, + stack: + '()@file:///G:/js/stacktrace.js:44\n' + + '(null)@file:///G:/js/stacktrace.js:31\n' + + 'printStackTrace()@file:///G:/js/stacktrace.js:18\n' + + 'bar(1)@file:///G:/js/file.js:13\n' + + 'bar(2)@file:///G:/js/file.js:16\n' + + 'foo()@file:///G:/js/file.js:20\n' + + '@file:///G:/js/file.js:24\n' + + '', + }; + + const stackFrames = computeStackTrace(FIREFOX_7); + + expect(stackFrames).toEqual({ + message: 'bar', + name: 'foo', + stack: [ + { url: 'file:///G:/js/stacktrace.js', func: '?', line: 44, column: null }, + { url: 'file:///G:/js/stacktrace.js', func: '?', line: 31, column: null }, + { url: 'file:///G:/js/stacktrace.js', func: 'printStackTrace', line: 18, column: null }, + { url: 'file:///G:/js/file.js', func: 'bar', line: 13, column: null }, + { url: 'file:///G:/js/file.js', func: 'bar', line: 16, column: null }, + { url: 'file:///G:/js/file.js', func: 'foo', line: 20, column: null }, + { url: 'file:///G:/js/file.js', func: '?', line: 24, column: null }, + ], + }); + }); + + it('should parse Firefox 14 error', () => { + const FIREFOX_14 = { + name: 'foo', + message: 'x is null', + stack: + '@http://path/to/file.js:48\n' + + 'dumpException3@http://path/to/file.js:52\n' + + 'onclick@http://path/to/file.js:1\n' + + '', + fileName: 'http://path/to/file.js', + lineNumber: 48, + }; + + const stackFrames = computeStackTrace(FIREFOX_14); + + expect(stackFrames).toEqual({ + message: 'x is null', + name: 'foo', + stack: [ + { url: 'http://path/to/file.js', func: '?', line: 48, column: null }, + { url: 'http://path/to/file.js', func: 'dumpException3', line: 52, column: null }, + { url: 'http://path/to/file.js', func: 'onclick', line: 1, column: null }, + ], + }); + }); + + it('should parse Firefox 31 error', () => { + const FIREFOX_31 = { + message: 'Default error', + name: 'Error', + stack: + 'foo@http://path/to/file.js:41:13\n' + + 'bar@http://path/to/file.js:1:1\n' + + '.plugin/e.fn[c]/<@http://path/to/file.js:1:1\n' + + '', + fileName: 'http://path/to/file.js', + lineNumber: 41, + columnNumber: 12, + }; + + const stackFrames = computeStackTrace(FIREFOX_31); + + expect(stackFrames).toEqual({ + message: 'Default error', + name: 'Error', + stack: [ + { url: 'http://path/to/file.js', func: 'foo', line: 41, column: 13 }, + { url: 'http://path/to/file.js', func: 'bar', line: 1, column: 1 }, + { url: 'http://path/to/file.js', func: '.plugin/e.fn[c]/<', line: 1, column: 1 }, + ], + }); + }); + + it('should parse Firefox 44 ns exceptions', () => { + // Internal errors sometimes thrown by Firefox + // More here: https://developer.mozilla.org/en-US/docs/Mozilla/Errors + // + // Note that such errors are instanceof "Exception", not "Error" + const FIREFOX_44_NS_EXCEPTION = { + message: '', + name: 'NS_ERROR_FAILURE', + stack: + '[2] tag + '', + fileName: 'http://path/to/file.js', + columnNumber: 0, + lineNumber: 703, + result: 2147500037, + }; + + const stackFrames = computeStackTrace(FIREFOX_44_NS_EXCEPTION); + + expect(stackFrames).toEqual({ + message: 'No error message', + name: 'NS_ERROR_FAILURE', + stack: [ + { url: 'http://path/to/file.js', func: '[2] { + const FIREFOX_50_RESOURCE_URL = { + stack: + 'render@resource://path/data/content/bundle.js:5529:16\n' + + 'dispatchEvent@resource://path/data/content/vendor.bundle.js:18:23028\n' + + 'wrapped@resource://path/data/content/bundle.js:7270:25', + fileName: 'resource://path/data/content/bundle.js', + lineNumber: 5529, + columnNumber: 16, + message: 'this.props.raw[this.state.dataSource].rows is undefined', + name: 'TypeError', + }; + + const stackFrames = computeStackTrace(FIREFOX_50_RESOURCE_URL); + + expect(stackFrames).toEqual({ + message: 'this.props.raw[this.state.dataSource].rows is undefined', + name: 'TypeError', + stack: [ + { url: 'resource://path/data/content/bundle.js', func: 'render', line: 5529, column: 16 }, + { url: 'resource://path/data/content/vendor.bundle.js', func: 'dispatchEvent', line: 18, column: 23028 }, + { url: 'resource://path/data/content/bundle.js', func: 'wrapped', line: 7270, column: 25 }, + ], + }); + }); + + it('should parse Firefox errors with eval URLs', () => { + const FIREFOX_43_EVAL = { + name: 'foo', + columnNumber: 30, + fileName: 'http://localhost:8080/file.js line 25 > eval line 2 > eval', + lineNumber: 1, + message: 'message string', + stack: + 'baz@http://localhost:8080/file.js line 26 > eval line 2 > eval:1:30\n' + + 'foo@http://localhost:8080/file.js line 26 > eval:2:96\n' + + '@http://localhost:8080/file.js line 26 > eval:4:18\n' + + 'speak@http://localhost:8080/file.js:26:17\n' + + '@http://localhost:8080/file.js:33:9', + }; + + const stackFrames = computeStackTrace(FIREFOX_43_EVAL); + + expect(stackFrames).toEqual({ + message: 'message string', + name: 'foo', + stack: [ + { url: 'http://localhost:8080/file.js', func: 'baz', line: 26, column: null }, + { url: 'http://localhost:8080/file.js', func: 'foo', line: 26, column: null }, + { url: 'http://localhost:8080/file.js', func: 'eval', line: 26, column: null }, + { url: 'http://localhost:8080/file.js', func: 'speak', line: 26, column: 17 }, + { url: 'http://localhost:8080/file.js', func: '?', line: 33, column: 9 }, + ], + }); + }); + + it('should parse exceptions with native code frames in Firefox 66', () => { + const FIREFOX66_NATIVE_CODE_EXCEPTION = { + message: 'test', + name: 'Error', + stack: `fooIterator@http://localhost:5000/test:20:17 + foo@http://localhost:5000/test:19:19 + @http://localhost:5000/test:24:7`, + }; + + const stacktrace = computeStackTrace(FIREFOX66_NATIVE_CODE_EXCEPTION); + + expect(stacktrace).toEqual({ + message: 'test', + name: 'Error', + stack: [ + { url: 'http://localhost:5000/test', func: 'fooIterator', line: 20, column: 17 }, + { url: 'http://localhost:5000/test', func: 'foo', line: 19, column: 19 }, + { url: 'http://localhost:5000/test', func: '?', line: 24, column: 7 }, + ], + }); + }); + + it('should parse exceptions with eval frames in Firefox 66', () => { + const FIREFOX66_EVAL_EXCEPTION = { + message: 'aha', + name: 'Error', + stack: `aha@http://localhost:5000/:19:13 + callAnotherThing@http://localhost:5000/:20:15 + callback@http://localhost:5000/:25:7 + test/<@http://localhost:5000/:34:7 + test@http://localhost:5000/:33:23 + @http://localhost:5000/ line 39 > eval:1:1 + aha@http://localhost:5000/:39:5 + testMethod@http://localhost:5000/:44:7 + @http://localhost:5000/:50:19`, + }; + + const stacktrace = computeStackTrace(FIREFOX66_EVAL_EXCEPTION); + + expect(stacktrace).toEqual({ + message: 'aha', + name: 'Error', + stack: [ + { url: 'http://localhost:5000/', func: 'aha', line: 19, column: 13 }, + { url: 'http://localhost:5000/', func: 'callAnotherThing', line: 20, column: 15 }, + { url: 'http://localhost:5000/', func: 'callback', line: 25, column: 7 }, + { url: 'http://localhost:5000/', func: 'test/<', line: 34, column: 7 }, + { url: 'http://localhost:5000/', func: 'test', line: 33, column: 23 }, + { url: 'http://localhost:5000/', func: 'eval', line: 39, column: null }, + { url: 'http://localhost:5000/', func: 'aha', line: 39, column: 5 }, + { url: 'http://localhost:5000/', func: 'testMethod', line: 44, column: 7 }, + { url: 'http://localhost:5000/', func: '?', line: 50, column: 19 }, + ], + }); + }); +}); diff --git a/packages/browser/test/unit/tracekit/ie.test.ts b/packages/browser/test/unit/tracekit/ie.test.ts new file mode 100644 index 000000000000..7d016802175d --- /dev/null +++ b/packages/browser/test/unit/tracekit/ie.test.ts @@ -0,0 +1,83 @@ +import { computeStackTrace } from '../../../src/tracekit'; + +describe('Tracekit - IE Tests', () => { + it('should parse IE 10 error', () => { + const IE_10 = { + name: 'foo', + message: "Unable to get property 'undef' of undefined or null reference", + stack: + "TypeError: Unable to get property 'undef' of undefined or null reference\n" + + ' at Anonymous function (http://path/to/file.js:48:13)\n' + + ' at foo (http://path/to/file.js:46:9)\n' + + ' at bar (http://path/to/file.js:82:1)', + description: "Unable to get property 'undef' of undefined or null reference", + number: -2146823281, + }; + + const stackFrames = computeStackTrace(IE_10); + + // TODO: func should be normalized + expect(stackFrames).toEqual({ + message: "Unable to get property 'undef' of undefined or null reference", + name: 'foo', + stack: [ + { url: 'http://path/to/file.js', func: 'Anonymous function', line: 48, column: 13 }, + { url: 'http://path/to/file.js', func: 'foo', line: 46, column: 9 }, + { url: 'http://path/to/file.js', func: 'bar', line: 82, column: 1 }, + ], + }); + }); + + it('should parse IE 11 error', () => { + const IE_11 = { + message: "Unable to get property 'undef' of undefined or null reference", + name: 'TypeError', + stack: + "TypeError: Unable to get property 'undef' of undefined or null reference\n" + + ' at Anonymous function (http://path/to/file.js:47:21)\n' + + ' at foo (http://path/to/file.js:45:13)\n' + + ' at bar (http://path/to/file.js:108:1)', + description: "Unable to get property 'undef' of undefined or null reference", + number: -2146823281, + }; + + const stackFrames = computeStackTrace(IE_11); + + // TODO: func should be normalized + expect(stackFrames).toEqual({ + message: "Unable to get property 'undef' of undefined or null reference", + name: 'TypeError', + stack: [ + { url: 'http://path/to/file.js', func: 'Anonymous function', line: 47, column: 21 }, + { url: 'http://path/to/file.js', func: 'foo', line: 45, column: 13 }, + { url: 'http://path/to/file.js', func: 'bar', line: 108, column: 1 }, + ], + }); + }); + + it('should parse IE 11 eval error', () => { + const IE_11_EVAL = { + message: "'getExceptionProps' is undefined", + name: 'ReferenceError', + stack: + "ReferenceError: 'getExceptionProps' is undefined\n" + + ' at eval code (eval code:1:1)\n' + + ' at foo (http://path/to/file.js:58:17)\n' + + ' at bar (http://path/to/file.js:109:1)', + description: "'getExceptionProps' is undefined", + number: -2146823279, + }; + + const stackFrames = computeStackTrace(IE_11_EVAL); + + expect(stackFrames).toEqual({ + message: "'getExceptionProps' is undefined", + name: 'ReferenceError', + stack: [ + { url: 'eval code', func: 'eval code', line: 1, column: 1 }, + { url: 'http://path/to/file.js', func: 'foo', line: 58, column: 17 }, + { url: 'http://path/to/file.js', func: 'bar', line: 109, column: 1 }, + ], + }); + }); +}); diff --git a/packages/browser/test/unit/tracekit/misc.test.ts b/packages/browser/test/unit/tracekit/misc.test.ts new file mode 100644 index 000000000000..0ec51e94c26a --- /dev/null +++ b/packages/browser/test/unit/tracekit/misc.test.ts @@ -0,0 +1,26 @@ +import { computeStackTrace } from '../../../src/tracekit'; + +describe('Tracekit - Misc Tests', () => { + it('should parse PhantomJS 1.19 error', () => { + const PHANTOMJS_1_19 = { + name: 'foo', + message: 'bar', + stack: + 'Error: foo\n' + + ' at file:///path/to/file.js:878\n' + + ' at foo (http://path/to/file.js:4283)\n' + + ' at http://path/to/file.js:4287', + }; + const stackFrames = computeStackTrace(PHANTOMJS_1_19); + + expect(stackFrames).toEqual({ + message: 'bar', + name: 'foo', + stack: [ + { url: 'file:///path/to/file.js', func: '?', line: 878, column: null }, + { url: 'http://path/to/file.js', func: 'foo', line: 4283, column: null }, + { url: 'http://path/to/file.js', func: '?', line: 4287, column: null }, + ], + }); + }); +}); diff --git a/packages/browser/test/unit/tracekit/opera.test.ts b/packages/browser/test/unit/tracekit/opera.test.ts new file mode 100644 index 000000000000..5df2ba4a78ae --- /dev/null +++ b/packages/browser/test/unit/tracekit/opera.test.ts @@ -0,0 +1,142 @@ +import { computeStackTrace } from '../../../src/tracekit'; + +describe('Tracekit - Opera Tests', () => { + it('should parse Opera 10 error', () => { + const OPERA_10 = { + name: 'foo', + message: 'Statement on line 42: Type mismatch (usually non-object value supplied where object required)', + 'opera#sourceloc': 42, + stacktrace: + ' Line 42 of linked script http://path/to/file.js\n' + + ' this.undef();\n' + + ' Line 27 of linked script http://path/to/file.js\n' + + ' ex = ex || this.createException();\n' + + ' Line 18 of linked script http://path/to/file.js: In function printStackTrace\n' + + ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + + ' Line 4 of inline#1 script in http://path/to/file.js: In function bar\n' + + ' printTrace(printStackTrace());\n' + + ' Line 7 of inline#1 script in http://path/to/file.js: In function bar\n' + + ' bar(n - 1);\n' + + ' Line 11 of inline#1 script in http://path/to/file.js: In function foo\n' + + ' bar(2);\n' + + ' Line 15 of inline#1 script in http://path/to/file.js\n' + + ' foo();\n' + + '', + }; + + const stackFrames = computeStackTrace(OPERA_10); + + expect(stackFrames).toEqual({ + message: 'Statement on line 42: Type mismatch (usually non-object value supplied where object required)', + name: 'foo', + stack: [ + { url: 'http://path/to/file.js', func: '?', line: 42, column: null }, + { url: 'http://path/to/file.js', func: '?', line: 27, column: null }, + { url: 'http://path/to/file.js', func: 'printStackTrace', line: 18, column: null }, + { url: 'http://path/to/file.js', func: 'bar', line: 4, column: null }, + { url: 'http://path/to/file.js', func: 'bar', line: 7, column: null }, + { url: 'http://path/to/file.js', func: 'foo', line: 11, column: null }, + { url: 'http://path/to/file.js', func: '?', line: 15, column: null }, + ], + }); + }); + + it('should parse Opera 11 error', () => { + const OPERA_11 = { + name: 'foo', + message: "'this.undef' is not a function", + stack: + '([arguments not available])@http://path/to/file.js:27\n' + + 'bar([arguments not available])@http://domain.com:1234/path/to/file.js:18\n' + + 'foo([arguments not available])@http://domain.com:1234/path/to/file.js:11\n' + + '@http://path/to/file.js:15\n' + + 'Error created at @http://path/to/file.js:15', + stacktrace: + 'Error thrown at line 42, column 12 in () in http://path/to/file.js:\n' + + ' this.undef();\n' + + 'called from line 27, column 8 in (ex) in http://path/to/file.js:\n' + + ' ex = ex || this.createException();\n' + + 'called from line 18, column 4 in printStackTrace(options) in http://path/to/file.js:\n' + + ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + + 'called from line 4, column 5 in bar(n) in http://path/to/file.js:\n' + + ' printTrace(printStackTrace());\n' + + 'called from line 7, column 4 in bar(n) in http://path/to/file.js:\n' + + ' bar(n - 1);\n' + + 'called from line 11, column 4 in foo() in http://path/to/file.js:\n' + + ' bar(2);\n' + + 'called from line 15, column 3 in http://path/to/file.js:\n' + + ' foo();', + }; + + const stackFrames = computeStackTrace(OPERA_11); + + expect(stackFrames).toEqual({ + message: "'this.undef' is not a function", + name: 'foo', + stack: [ + { url: 'http://path/to/file.js', func: 'createException', line: 42, column: 12 }, + { url: 'http://path/to/file.js', func: 'run', line: 27, column: 8 }, + { url: 'http://path/to/file.js', func: 'printStackTrace', line: 18, column: 4 }, + { url: 'http://path/to/file.js', func: 'bar', line: 4, column: 5 }, + { url: 'http://path/to/file.js', func: 'bar', line: 7, column: 4 }, + { url: 'http://path/to/file.js', func: 'foo', line: 11, column: 4 }, + { url: 'http://path/to/file.js', func: '?', line: 15, column: 3 }, + ], + }); + }); + + it('should parse Opera 12 error', () => { + // TODO: Improve anonymous function name. + const OPERA_12 = { + name: 'foo', + message: "Cannot convert 'x' to object", + stack: + '([arguments not available])@http://localhost:8000/ExceptionLab.html:48\n' + + 'dumpException3([arguments not available])@http://localhost:8000/ExceptionLab.html:46\n' + + '([arguments not available])@http://localhost:8000/ExceptionLab.html:1', + stacktrace: + 'Error thrown at line 48, column 12 in (x) in http://localhost:8000/ExceptionLab.html:\n' + + ' x.undef();\n' + + 'called from line 46, column 8 in dumpException3() in http://localhost:8000/ExceptionLab.html:\n' + + ' dumpException((function(x) {\n' + + 'called from line 1, column 0 in (event) in http://localhost:8000/ExceptionLab.html:\n' + + ' dumpException3();', + }; + + const stackFrames = computeStackTrace(OPERA_12); + + expect(stackFrames).toEqual({ + message: "Cannot convert 'x' to object", + name: 'foo', + stack: [ + { url: 'http://localhost:8000/ExceptionLab.html', func: '', line: 48, column: 12 }, + { url: 'http://localhost:8000/ExceptionLab.html', func: 'dumpException3', line: 46, column: 8 }, + { url: 'http://localhost:8000/ExceptionLab.html', func: '', line: 1, column: 0 }, + ], + }); + }); + + it('should parse Opera 25 error', () => { + const OPERA_25 = { + message: "Cannot read property 'undef' of null", + name: 'TypeError', + stack: + "TypeError: Cannot read property 'undef' of null\n" + + ' at http://path/to/file.js:47:22\n' + + ' at foo (http://path/to/file.js:52:15)\n' + + ' at bar (http://path/to/file.js:108:168)', + }; + + const stackFrames = computeStackTrace(OPERA_25); + + expect(stackFrames).toEqual({ + message: "Cannot read property 'undef' of null", + name: 'TypeError', + stack: [ + { url: 'http://path/to/file.js', func: '?', line: 47, column: 22 }, + { url: 'http://path/to/file.js', func: 'foo', line: 52, column: 15 }, + { url: 'http://path/to/file.js', func: 'bar', line: 108, column: 168 }, + ], + }); + }); +}); diff --git a/packages/browser/test/unit/tracekit/original.test.ts b/packages/browser/test/unit/tracekit/original.test.ts deleted file mode 100644 index 1ec59f3e3ac3..000000000000 --- a/packages/browser/test/unit/tracekit/original.test.ts +++ /dev/null @@ -1,938 +0,0 @@ -import { computeStackTrace } from '../../../src/tracekit'; -import { - ANDROID_REACT_NATIVE, - ANDROID_REACT_NATIVE_HERMES, - ANDROID_REACT_NATIVE_PROD, - CHROME_15, - CHROME_36, - CHROME_48_BLOB, - CHROME_48_EVAL, - CHROME_XX_WEBPACK, - FIREFOX_3, - FIREFOX_7, - FIREFOX_14, - FIREFOX_31, - FIREFOX_43_EVAL, - FIREFOX_44_NS_EXCEPTION, - FIREFOX_50_RESOURCE_URL, - IE_10, - IE_11, - IE_11_EVAL, - OPERA_10, - OPERA_11, - OPERA_12, - OPERA_25, - PHANTOMJS_1_19, - SAFARI_6, - SAFARI_7, - SAFARI_8, - SAFARI_8_EVAL, -} from './originalfixtures'; - -describe('Tracekit - Original Tests', () => { - it('should parse Safari 6 error', () => { - const stackFrames = computeStackTrace(SAFARI_6); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(4); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://path/to/file.js', - func: '?', - args: [], - line: 48, - column: null, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: 'dumpException3', - args: [], - line: 52, - column: null, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: 'onclick', - args: [], - line: 82, - column: null, - }); - expect(stackFrames.stack[3]).toEqual({ - url: '[native code]', - func: '?', - args: [], - line: null, - column: null, - }); - }); - - it('should parse Safari 7 error', () => { - const stackFrames = computeStackTrace(SAFARI_7); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(3); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://path/to/file.js', - func: '?', - args: [], - line: 48, - column: 22, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: 'foo', - args: [], - line: 52, - column: 15, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: [], - line: 108, - column: 107, - }); - }); - - it('should parse Safari 8 error', () => { - const stackFrames = computeStackTrace(SAFARI_8); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(3); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://path/to/file.js', - func: '?', - args: [], - line: 47, - column: 22, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: 'foo', - args: [], - line: 52, - column: 15, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: [], - line: 108, - column: 23, - }); - }); - - it('should parse Safari 8 eval error', () => { - // TODO: Take into account the line and column properties on the error object and use them for the first stack trace. - const stackFrames = computeStackTrace(SAFARI_8_EVAL); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(3); - expect(stackFrames.stack[0]).toEqual({ - url: '[native code]', - func: 'eval', - args: [], - line: null, - column: null, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: 'foo', - args: [], - line: 58, - column: 21, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: [], - line: 109, - column: 91, - }); - }); - - it('should parse Firefox 3 error', () => { - const stackFrames = computeStackTrace(FIREFOX_3); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(7); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://127.0.0.1:8000/js/stacktrace.js', - func: '?', - args: [], - line: 44, - column: null, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://127.0.0.1:8000/js/stacktrace.js', - func: '?', - args: ['null'], - line: 31, - column: null, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://127.0.0.1:8000/js/stacktrace.js', - func: 'printStackTrace', - args: [], - line: 18, - column: null, - }); - expect(stackFrames.stack[3]).toEqual({ - url: 'http://127.0.0.1:8000/js/file.js', - func: 'bar', - args: ['1'], - line: 13, - column: null, - }); - expect(stackFrames.stack[4]).toEqual({ - url: 'http://127.0.0.1:8000/js/file.js', - func: 'bar', - args: ['2'], - line: 16, - column: null, - }); - expect(stackFrames.stack[5]).toEqual({ - url: 'http://127.0.0.1:8000/js/file.js', - func: 'foo', - args: [], - line: 20, - column: null, - }); - expect(stackFrames.stack[6]).toEqual({ - url: 'http://127.0.0.1:8000/js/file.js', - func: '?', - args: [], - line: 24, - column: null, - }); - }); - - it('should parse Firefox 7 error', () => { - const stackFrames = computeStackTrace(FIREFOX_7); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(7); - expect(stackFrames.stack[0]).toEqual({ - url: 'file:///G:/js/stacktrace.js', - func: '?', - args: [], - line: 44, - column: null, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'file:///G:/js/stacktrace.js', - func: '?', - args: ['null'], - line: 31, - column: null, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'file:///G:/js/stacktrace.js', - func: 'printStackTrace', - args: [], - line: 18, - column: null, - }); - expect(stackFrames.stack[3]).toEqual({ - url: 'file:///G:/js/file.js', - func: 'bar', - args: ['1'], - line: 13, - column: null, - }); - expect(stackFrames.stack[4]).toEqual({ - url: 'file:///G:/js/file.js', - func: 'bar', - args: ['2'], - line: 16, - column: null, - }); - expect(stackFrames.stack[5]).toEqual({ - url: 'file:///G:/js/file.js', - func: 'foo', - args: [], - line: 20, - column: null, - }); - expect(stackFrames.stack[6]).toEqual({ - url: 'file:///G:/js/file.js', - func: '?', - args: [], - line: 24, - column: null, - }); - }); - - it('should parse Firefox 14 error', () => { - const stackFrames = computeStackTrace(FIREFOX_14); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(3); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://path/to/file.js', - func: '?', - args: [], - line: 48, - column: null, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: 'dumpException3', - args: [], - line: 52, - column: null, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: 'onclick', - args: [], - line: 1, - column: null, - }); - }); - - it('should parse Firefox 31 error', () => { - const stackFrames = computeStackTrace(FIREFOX_31); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(3); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://path/to/file.js', - func: 'foo', - args: [], - line: 41, - column: 13, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: [], - line: 1, - column: 1, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: '.plugin/e.fn[c]/<', - args: [], - line: 1, - column: 1, - }); - }); - - it('should parse Firefox 44 ns exceptions', () => { - const stackFrames = computeStackTrace(FIREFOX_44_NS_EXCEPTION); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(4); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://path/to/file.js', - func: '[2] { - const stackFrames = computeStackTrace({ message: 'foo', name: 'bar', stack: 'error\n at Array.forEach (native)' }); - expect(stackFrames.stack.length).toBe(1); - expect(stackFrames.stack[0]).toEqual({ - url: 'native', - func: 'Array.forEach', - args: ['native'], - line: null, - column: null, - }); - }); - - it('should parse Chrome 15 error', () => { - const stackFrames = computeStackTrace(CHROME_15); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(4); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: [], - line: 13, - column: 17, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: [], - line: 16, - column: 5, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: 'foo', - args: [], - line: 20, - column: 5, - }); - expect(stackFrames.stack[3]).toEqual({ - url: 'http://path/to/file.js', - func: '?', - args: [], - line: 24, - column: 4, - }); - }); - - it('should parse Chrome 36 error with port numbers', () => { - const stackFrames = computeStackTrace(CHROME_36); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(3); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://localhost:8080/file.js', - func: 'dumpExceptionError', - args: [], - line: 41, - column: 27, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://localhost:8080/file.js', - func: 'HTMLButtonElement.onclick', - args: [], - line: 107, - column: 146, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://localhost:8080/file.js', - func: 'I.e.fn.(anonymous function) [as index]', - args: [], - line: 10, - column: 3651, - }); - }); - - it('should parse Chrome error with webpack URLs', () => { - const stackFrames = computeStackTrace(CHROME_XX_WEBPACK); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(4); - expect(stackFrames.stack[0]).toEqual({ - url: 'webpack:///./src/components/test/test.jsx?', - func: 'TESTTESTTEST.eval', - args: [], - line: 295, - column: 108, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'webpack:///./src/components/test/test.jsx?', - func: 'TESTTESTTEST.render', - args: [], - line: 272, - column: 32, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'webpack:///./~/react-transform-catch-errors/lib/index.js?', - func: 'TESTTESTTEST.tryRender', - args: [], - line: 34, - column: 31, - }); - expect(stackFrames.stack[3]).toEqual({ - url: 'webpack:///./~/react-proxy/modules/createPrototypeProxy.js?', - func: 'TESTTESTTEST.proxiedMethod', - args: [], - line: 44, - column: 30, - }); - }); - - it('should parse nested eval() from Chrome', () => { - const stackFrames = computeStackTrace(CHROME_48_EVAL); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(5); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://localhost:8080/file.js', - func: 'baz', - args: [], - line: 21, - column: 17, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://localhost:8080/file.js', - func: 'foo', - args: [], - line: 21, - column: 17, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://localhost:8080/file.js', - func: 'eval', - args: [], - line: 21, - column: 17, - }); - expect(stackFrames.stack[3]).toEqual({ - url: 'http://localhost:8080/file.js', - func: 'Object.speak', - args: [], - line: 21, - column: 17, - }); - expect(stackFrames.stack[4]).toEqual({ - url: 'http://localhost:8080/file.js', - func: '?', - args: [], - line: 31, - column: 13, - }); - }); - - it('should parse Chrome error with blob URLs', () => { - const stackFrames = computeStackTrace(CHROME_48_BLOB); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(7); - expect(stackFrames.stack[1]).toEqual({ - url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', - func: 's', - args: [], - line: 31, - column: 29146, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', - func: 'Object.d [as add]', - args: [], - line: 31, - column: 30039, - }); - expect(stackFrames.stack[3]).toEqual({ - url: 'blob:http%3A//localhost%3A8080/d4eefe0f-361a-4682-b217-76587d9f712a', - func: '?', - args: [], - line: 15, - column: 10978, - }); - expect(stackFrames.stack[4]).toEqual({ - url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', - func: '?', - args: [], - line: 1, - column: 6911, - }); - expect(stackFrames.stack[5]).toEqual({ - url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', - func: 'n.fire', - args: [], - line: 7, - column: 3019, - }); - expect(stackFrames.stack[6]).toEqual({ - url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', - func: 'n.handle', - args: [], - line: 7, - column: 2863, - }); - }); - - it('should parse IE 10 error', () => { - const stackFrames = computeStackTrace(IE_10); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(3); - // TODO: func should be normalized - expect(stackFrames.stack[0]).toEqual({ - url: 'http://path/to/file.js', - func: 'Anonymous function', - args: [], - line: 48, - column: 13, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: 'foo', - args: [], - line: 46, - column: 9, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: [], - line: 82, - column: 1, - }); - }); - - it('should parse IE 11 error', () => { - const stackFrames = computeStackTrace(IE_11); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(3); - // TODO: func should be normalized - expect(stackFrames.stack[0]).toEqual({ - url: 'http://path/to/file.js', - func: 'Anonymous function', - args: [], - line: 47, - column: 21, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: 'foo', - args: [], - line: 45, - column: 13, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: [], - line: 108, - column: 1, - }); - }); - - it('should parse IE 11 eval error', () => { - const stackFrames = computeStackTrace(IE_11_EVAL); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(3); - expect(stackFrames.stack[0]).toEqual({ - url: 'eval code', - func: 'eval code', - args: [], - line: 1, - column: 1, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: 'foo', - args: [], - line: 58, - column: 17, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: [], - line: 109, - column: 1, - }); - }); - - it('should parse Opera 10 error', () => { - const stackFrames = computeStackTrace(OPERA_10); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(7); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://path/to/file.js', - func: '?', - args: [], - line: 42, - column: null, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: '?', - args: [], - line: 27, - column: null, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: 'printStackTrace', - args: [], - line: 18, - column: null, - }); - expect(stackFrames.stack[3]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: [], - line: 4, - column: null, - }); - expect(stackFrames.stack[4]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: [], - line: 7, - column: null, - }); - expect(stackFrames.stack[5]).toEqual({ - url: 'http://path/to/file.js', - func: 'foo', - args: [], - line: 11, - column: null, - }); - expect(stackFrames.stack[6]).toEqual({ - url: 'http://path/to/file.js', - func: '?', - args: [], - line: 15, - column: null, - }); - }); - - it('should parse Opera 11 error', () => { - const stackFrames = computeStackTrace(OPERA_11); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(7); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://path/to/file.js', - func: 'createException', - args: [], - line: 42, - column: 12, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: 'run', - args: ['ex'], - line: 27, - column: 8, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: 'printStackTrace', - args: ['options'], - line: 18, - column: 4, - }); - expect(stackFrames.stack[3]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: ['n'], - line: 4, - column: 5, - }); - expect(stackFrames.stack[4]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: ['n'], - line: 7, - column: 4, - }); - expect(stackFrames.stack[5]).toEqual({ - url: 'http://path/to/file.js', - func: 'foo', - args: [], - line: 11, - column: 4, - }); - expect(stackFrames.stack[6]).toEqual({ - url: 'http://path/to/file.js', - func: '?', - args: [], - line: 15, - column: 3, - }); - }); - - it('should parse Opera 12 error', () => { - // TODO: Improve anonymous function name. - const stackFrames = computeStackTrace(OPERA_12); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(3); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://localhost:8000/ExceptionLab.html', - func: '', - args: ['x'], - line: 48, - column: 12, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://localhost:8000/ExceptionLab.html', - func: 'dumpException3', - args: [], - line: 46, - column: 8, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://localhost:8000/ExceptionLab.html', - func: '', - args: ['event'], - line: 1, - column: 0, - }); - }); - - it('should parse Opera 25 error', () => { - const stackFrames = computeStackTrace(OPERA_25); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(3); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://path/to/file.js', - func: '?', - args: [], - line: 47, - column: 22, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: 'foo', - args: [], - line: 52, - column: 15, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: 'bar', - args: [], - line: 108, - column: 168, - }); - }); - - it('should parse PhantomJS 1.19 error', () => { - const stackFrames = computeStackTrace(PHANTOMJS_1_19); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(3); - expect(stackFrames.stack[0]).toEqual({ - url: 'file:///path/to/file.js', - func: '?', - args: [], - line: 878, - column: null, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://path/to/file.js', - func: 'foo', - args: [], - line: 4283, - column: null, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://path/to/file.js', - func: '?', - args: [], - line: 4287, - column: null, - }); - }); - - it('should parse Firefox errors with resource: URLs', () => { - const stackFrames = computeStackTrace(FIREFOX_50_RESOURCE_URL); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(3); - expect(stackFrames.stack[0]).toEqual({ - url: 'resource://path/data/content/bundle.js', - func: 'render', - args: [], - line: 5529, - column: 16, - }); - }); - - it('should parse Firefox errors with eval URLs', () => { - const stackFrames = computeStackTrace(FIREFOX_43_EVAL); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(5); - expect(stackFrames.stack[0]).toEqual({ - url: 'http://localhost:8080/file.js', - func: 'baz', - args: [], - line: 26, - column: null, - }); - expect(stackFrames.stack[1]).toEqual({ - url: 'http://localhost:8080/file.js', - func: 'foo', - args: [], - line: 26, - column: null, - }); - expect(stackFrames.stack[2]).toEqual({ - url: 'http://localhost:8080/file.js', - func: 'eval', - args: [], - line: 26, - column: null, - }); - expect(stackFrames.stack[3]).toEqual({ - url: 'http://localhost:8080/file.js', - func: 'speak', - args: [], - line: 26, - column: 17, - }); - expect(stackFrames.stack[4]).toEqual({ - url: 'http://localhost:8080/file.js', - func: '?', - args: [], - line: 33, - column: 9, - }); - }); - - it('should parse React Native errors on Android', () => { - const stackFrames = computeStackTrace(ANDROID_REACT_NATIVE); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(8); - expect(stackFrames.stack[0]).toEqual({ - url: '/home/username/sample-workspace/sampleapp.collect.react/src/components/GpsMonitorScene.js', - func: 'render', - args: [], - line: 78, - column: 24, - }); - expect(stackFrames.stack[7]).toEqual({ - url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/native/ReactNativeBaseComponent.js', - func: 'this', - args: [], - line: 74, - column: 41, - }); - }); - - it('should parse React Native errors on Android Production', () => { - const stackFrames = computeStackTrace(ANDROID_REACT_NATIVE_PROD); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(37); - expect(stackFrames.stack[0]).toEqual({ - url: 'index.android.bundle', - func: 'value', - args: [], - line: 12, - column: 1917, - }); - expect(stackFrames.stack[35]).toEqual({ - url: 'index.android.bundle', - func: 'value', - args: [], - line: 29, - column: 927, - }); - expect(stackFrames.stack[36]).toEqual({ - url: '[native code]', - func: '?', - args: [], - line: null, - column: null, - }); - }); - - it('should parse React Native errors on Android Hermes', () => { - const stackFrames = computeStackTrace(ANDROID_REACT_NATIVE_HERMES); - expect(stackFrames).toBeTruthy(); - expect(stackFrames.stack.length).toBe(26); - expect(stackFrames.stack[0]).toEqual({ - url: 'index.android.bundle', - func: 'onPress', - args: [], - line: 1, - column: 452701, - }); - expect(stackFrames.stack[3]).toEqual({ - url: 'native', - func: '_receiveSignal', - args: ['native'], - line: null, - column: null, - }); - }); -}); diff --git a/packages/browser/test/unit/tracekit/originalfixtures.ts b/packages/browser/test/unit/tracekit/originalfixtures.ts deleted file mode 100644 index 2f9977c3084b..000000000000 --- a/packages/browser/test/unit/tracekit/originalfixtures.ts +++ /dev/null @@ -1,513 +0,0 @@ -export const OPERA_854 = { - name: 'foo', - message: - 'Statement on line 44: Type mismatch (usually a non-object value used where an object is required)\n' + - 'Backtrace:\n' + - ' Line 44 of linked script http://path/to/file.js\n' + - ' this.undef();\n' + - ' Line 31 of linked script http://path/to/file.js\n' + - ' ex = ex || this.createException();\n' + - ' Line 18 of linked script http://path/to/file.js\n' + - ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + - ' Line 4 of inline#1 script in http://path/to/file.js\n' + - ' printTrace(printStackTrace());\n' + - ' Line 7 of inline#1 script in http://path/to/file.js\n' + - ' bar(n - 1);\n' + - ' Line 11 of inline#1 script in http://path/to/file.js\n' + - ' bar(2);\n' + - ' Line 15 of inline#1 script in http://path/to/file.js\n' + - ' foo();\n' + - '', - 'opera#sourceloc': 44, -}; - -export const OPERA_902 = { - name: 'foo', - message: - 'Statement on line 44: Type mismatch (usually a non-object value used where an object is required)\n' + - 'Backtrace:\n' + - ' Line 44 of linked script http://path/to/file.js\n' + - ' this.undef();\n' + - ' Line 31 of linked script http://path/to/file.js\n' + - ' ex = ex || this.createException();\n' + - ' Line 18 of linked script http://path/to/file.js\n' + - ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + - ' Line 4 of inline#1 script in http://path/to/file.js\n' + - ' printTrace(printStackTrace());\n' + - ' Line 7 of inline#1 script in http://path/to/file.js\n' + - ' bar(n - 1);\n' + - ' Line 11 of inline#1 script in http://path/to/file.js\n' + - ' bar(2);\n' + - ' Line 15 of inline#1 script in http://path/to/file.js\n' + - ' foo();\n' + - '', - 'opera#sourceloc': 44, -}; - -export const OPERA_927 = { - name: 'foo', - message: - 'Statement on line 43: Type mismatch (usually a non-object value used where an object is required)\n' + - 'Backtrace:\n' + - ' Line 43 of linked script http://path/to/file.js\n' + - ' bar(n - 1);\n' + - ' Line 31 of linked script http://path/to/file.js\n' + - ' bar(2);\n' + - ' Line 18 of linked script http://path/to/file.js\n' + - ' foo();\n' + - '', - 'opera#sourceloc': 43, -}; - -export const OPERA_964 = { - name: 'foo', - message: - 'Statement on line 42: Type mismatch (usually non-object value supplied where object required)\n' + - 'Backtrace:\n' + - ' Line 42 of linked script http://path/to/file.js\n' + - ' this.undef();\n' + - ' Line 27 of linked script http://path/to/file.js\n' + - ' ex = ex || this.createException();\n' + - ' Line 18 of linked script http://path/to/file.js: In function printStackTrace\n' + - ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + - ' Line 4 of inline#1 script in http://path/to/file.js: In function bar\n' + - ' printTrace(printStackTrace());\n' + - ' Line 7 of inline#1 script in http://path/to/file.js: In function bar\n' + - ' bar(n - 1);\n' + - ' Line 11 of inline#1 script in http://path/to/file.js: In function foo\n' + - ' bar(2);\n' + - ' Line 15 of inline#1 script in http://path/to/file.js\n' + - ' foo();\n' + - '', - 'opera#sourceloc': 42, - stacktrace: - ' ... Line 27 of linked script http://path/to/file.js\n' + - ' ex = ex || this.createException();\n' + - ' Line 18 of linked script http://path/to/file.js: In function printStackTrace\n' + - ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + - ' Line 4 of inline#1 script in http://path/to/file.js: In function bar\n' + - ' printTrace(printStackTrace());\n' + - ' Line 7 of inline#1 script in http://path/to/file.js: In function bar\n' + - ' bar(n - 1);\n' + - ' Line 11 of inline#1 script in http://path/to/file.js: In function foo\n' + - ' bar(2);\n' + - ' Line 15 of inline#1 script in http://path/to/file.js\n' + - ' foo();\n' + - '', -}; - -export const OPERA_10 = { - name: 'foo', - message: 'Statement on line 42: Type mismatch (usually non-object value supplied where object required)', - 'opera#sourceloc': 42, - stacktrace: - ' Line 42 of linked script http://path/to/file.js\n' + - ' this.undef();\n' + - ' Line 27 of linked script http://path/to/file.js\n' + - ' ex = ex || this.createException();\n' + - ' Line 18 of linked script http://path/to/file.js: In function printStackTrace\n' + - ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + - ' Line 4 of inline#1 script in http://path/to/file.js: In function bar\n' + - ' printTrace(printStackTrace());\n' + - ' Line 7 of inline#1 script in http://path/to/file.js: In function bar\n' + - ' bar(n - 1);\n' + - ' Line 11 of inline#1 script in http://path/to/file.js: In function foo\n' + - ' bar(2);\n' + - ' Line 15 of inline#1 script in http://path/to/file.js\n' + - ' foo();\n' + - '', -}; - -export const OPERA_11 = { - name: 'foo', - message: "'this.undef' is not a function", - stack: - '([arguments not available])@http://path/to/file.js:27\n' + - 'bar([arguments not available])@http://domain.com:1234/path/to/file.js:18\n' + - 'foo([arguments not available])@http://domain.com:1234/path/to/file.js:11\n' + - '@http://path/to/file.js:15\n' + - 'Error created at @http://path/to/file.js:15', - stacktrace: - 'Error thrown at line 42, column 12 in () in http://path/to/file.js:\n' + - ' this.undef();\n' + - 'called from line 27, column 8 in (ex) in http://path/to/file.js:\n' + - ' ex = ex || this.createException();\n' + - 'called from line 18, column 4 in printStackTrace(options) in http://path/to/file.js:\n' + - ' var p = new printStackTrace.implementation(), result = p.run(ex);\n' + - 'called from line 4, column 5 in bar(n) in http://path/to/file.js:\n' + - ' printTrace(printStackTrace());\n' + - 'called from line 7, column 4 in bar(n) in http://path/to/file.js:\n' + - ' bar(n - 1);\n' + - 'called from line 11, column 4 in foo() in http://path/to/file.js:\n' + - ' bar(2);\n' + - 'called from line 15, column 3 in http://path/to/file.js:\n' + - ' foo();', -}; - -export const OPERA_12 = { - name: 'foo', - message: "Cannot convert 'x' to object", - stack: - '([arguments not available])@http://localhost:8000/ExceptionLab.html:48\n' + - 'dumpException3([arguments not available])@http://localhost:8000/ExceptionLab.html:46\n' + - '([arguments not available])@http://localhost:8000/ExceptionLab.html:1', - stacktrace: - 'Error thrown at line 48, column 12 in (x) in http://localhost:8000/ExceptionLab.html:\n' + - ' x.undef();\n' + - 'called from line 46, column 8 in dumpException3() in http://localhost:8000/ExceptionLab.html:\n' + - ' dumpException((function(x) {\n' + - 'called from line 1, column 0 in (event) in http://localhost:8000/ExceptionLab.html:\n' + - ' dumpException3();', -}; - -export const OPERA_25 = { - message: "Cannot read property 'undef' of null", - name: 'TypeError', - stack: - "TypeError: Cannot read property 'undef' of null\n" + - ' at http://path/to/file.js:47:22\n' + - ' at foo (http://path/to/file.js:52:15)\n' + - ' at bar (http://path/to/file.js:108:168)', -}; - -export const CHROME_15 = { - name: 'foo', - arguments: ['undef'], - message: "Object # has no method 'undef'", - stack: - "TypeError: Object # has no method 'undef'\n" + - ' at bar (http://path/to/file.js:13:17)\n' + - ' at bar (http://path/to/file.js:16:5)\n' + - ' at foo (http://path/to/file.js:20:5)\n' + - ' at http://path/to/file.js:24:4', -}; - -export const CHROME_36 = { - message: 'Default error', - name: 'Error', - stack: - 'Error: Default error\n' + - ' at dumpExceptionError (http://localhost:8080/file.js:41:27)\n' + - ' at HTMLButtonElement.onclick (http://localhost:8080/file.js:107:146)\n' + - ' at I.e.fn.(anonymous function) [as index] (http://localhost:8080/file.js:10:3651)', -}; - -// can be generated when Webpack is built with { devtool: eval } -export const CHROME_XX_WEBPACK = { - message: "Cannot read property 'error' of undefined", - name: 'TypeError', - stack: - "TypeError: Cannot read property 'error' of undefined\n" + - ' at TESTTESTTEST.eval(webpack:///./src/components/test/test.jsx?:295:108)\n' + - ' at TESTTESTTEST.render(webpack:///./src/components/test/test.jsx?:272:32)\n' + - ' at TESTTESTTEST.tryRender(webpack:///./~/react-transform-catch-errors/lib/index.js?:34:31)\n' + - ' at TESTTESTTEST.proxiedMethod(webpack:///./~/react-proxy/modules/createPrototypeProxy.js?:44:30)', -}; - -export const FIREFOX_3 = { - fileName: 'http://127.0.0.1:8000/js/stacktrace.js', - lineNumber: 44, - message: 'this.undef is not a function', - name: 'TypeError', - stack: - '()@http://127.0.0.1:8000/js/stacktrace.js:44\n' + - '(null)@http://127.0.0.1:8000/js/stacktrace.js:31\n' + - 'printStackTrace()@http://127.0.0.1:8000/js/stacktrace.js:18\n' + - 'bar(1)@http://127.0.0.1:8000/js/file.js:13\n' + - 'bar(2)@http://127.0.0.1:8000/js/file.js:16\n' + - 'foo()@http://127.0.0.1:8000/js/file.js:20\n' + - '@http://127.0.0.1:8000/js/file.js:24\n' + - '', -}; - -export const FIREFOX_7 = { - name: 'foo', - message: 'bar', - fileName: 'file:///G:/js/stacktrace.js', - lineNumber: 44, - stack: - '()@file:///G:/js/stacktrace.js:44\n' + - '(null)@file:///G:/js/stacktrace.js:31\n' + - 'printStackTrace()@file:///G:/js/stacktrace.js:18\n' + - 'bar(1)@file:///G:/js/file.js:13\n' + - 'bar(2)@file:///G:/js/file.js:16\n' + - 'foo()@file:///G:/js/file.js:20\n' + - '@file:///G:/js/file.js:24\n' + - '', -}; - -export const FIREFOX_14 = { - name: 'foo', - message: 'x is null', - stack: - '@http://path/to/file.js:48\n' + - 'dumpException3@http://path/to/file.js:52\n' + - 'onclick@http://path/to/file.js:1\n' + - '', - fileName: 'http://path/to/file.js', - lineNumber: 48, -}; - -export const FIREFOX_31 = { - message: 'Default error', - name: 'Error', - stack: - 'foo@http://path/to/file.js:41:13\n' + - 'bar@http://path/to/file.js:1:1\n' + - '.plugin/e.fn[c]/<@http://path/to/file.js:1:1\n' + - '', - fileName: 'http://path/to/file.js', - lineNumber: 41, - columnNumber: 12, -}; - -export const FIREFOX_43_EVAL = { - name: 'foo', - columnNumber: 30, - fileName: 'http://localhost:8080/file.js line 25 > eval line 2 > eval', - lineNumber: 1, - message: 'message string', - stack: - 'baz@http://localhost:8080/file.js line 26 > eval line 2 > eval:1:30\n' + - 'foo@http://localhost:8080/file.js line 26 > eval:2:96\n' + - '@http://localhost:8080/file.js line 26 > eval:4:18\n' + - 'speak@http://localhost:8080/file.js:26:17\n' + - '@http://localhost:8080/file.js:33:9', -}; - -// Internal errors sometimes thrown by Firefox -// More here: https://developer.mozilla.org/en-US/docs/Mozilla/Errors -// -// Note that such errors are instanceof "Exception", not "Error" -export const FIREFOX_44_NS_EXCEPTION = { - message: '', - name: 'NS_ERROR_FAILURE', - stack: - '[2] tag - '', - fileName: 'http://path/to/file.js', - columnNumber: 0, - lineNumber: 703, - result: 2147500037, -}; - -export const FIREFOX_50_RESOURCE_URL = { - stack: - 'render@resource://path/data/content/bundle.js:5529:16\n' + - 'dispatchEvent@resource://path/data/content/vendor.bundle.js:18:23028\n' + - 'wrapped@resource://path/data/content/bundle.js:7270:25', - fileName: 'resource://path/data/content/bundle.js', - lineNumber: 5529, - columnNumber: 16, - message: 'this.props.raw[this.state.dataSource].rows is undefined', - name: 'TypeError', -}; - -export const SAFARI_6 = { - name: 'foo', - message: "'null' is not an object (evaluating 'x.undef')", - stack: - '@http://path/to/file.js:48\n' + - 'dumpException3@http://path/to/file.js:52\n' + - 'onclick@http://path/to/file.js:82\n' + - '[native code]', - line: 48, - sourceURL: 'http://path/to/file.js', -}; - -export const SAFARI_7 = { - message: "'null' is not an object (evaluating 'x.undef')", - name: 'TypeError', - stack: 'http://path/to/file.js:48:22\n' + 'foo@http://path/to/file.js:52:15\n' + 'bar@http://path/to/file.js:108:107', - line: 47, - sourceURL: 'http://path/to/file.js', -}; - -export const SAFARI_8 = { - message: "null is not an object (evaluating 'x.undef')", - name: 'TypeError', - stack: 'http://path/to/file.js:47:22\n' + 'foo@http://path/to/file.js:52:15\n' + 'bar@http://path/to/file.js:108:23', - line: 47, - column: 22, - sourceURL: 'http://path/to/file.js', -}; - -export const SAFARI_8_EVAL = { - message: "Can't find variable: getExceptionProps", - name: 'ReferenceError', - stack: - 'eval code\n' + 'eval@[native code]\n' + 'foo@http://path/to/file.js:58:21\n' + 'bar@http://path/to/file.js:109:91', - line: 1, - column: 18, -}; - -export const IE_9 = { - name: 'foo', - message: "Unable to get property 'undef' of undefined or null reference", - description: "Unable to get property 'undef' of undefined or null reference", -}; - -export const IE_10 = { - name: 'foo', - message: "Unable to get property 'undef' of undefined or null reference", - stack: - "TypeError: Unable to get property 'undef' of undefined or null reference\n" + - ' at Anonymous function (http://path/to/file.js:48:13)\n' + - ' at foo (http://path/to/file.js:46:9)\n' + - ' at bar (http://path/to/file.js:82:1)', - description: "Unable to get property 'undef' of undefined or null reference", - number: -2146823281, -}; - -export const IE_11 = { - message: "Unable to get property 'undef' of undefined or null reference", - name: 'TypeError', - stack: - "TypeError: Unable to get property 'undef' of undefined or null reference\n" + - ' at Anonymous function (http://path/to/file.js:47:21)\n' + - ' at foo (http://path/to/file.js:45:13)\n' + - ' at bar (http://path/to/file.js:108:1)', - description: "Unable to get property 'undef' of undefined or null reference", - number: -2146823281, -}; - -export const IE_11_EVAL = { - message: "'getExceptionProps' is undefined", - name: 'ReferenceError', - stack: - "ReferenceError: 'getExceptionProps' is undefined\n" + - ' at eval code (eval code:1:1)\n' + - ' at foo (http://path/to/file.js:58:17)\n' + - ' at bar (http://path/to/file.js:109:1)', - description: "'getExceptionProps' is undefined", - number: -2146823279, -}; - -export const CHROME_48_BLOB = { - message: 'Error: test', - name: 'Error', - stack: - 'Error: test\n' + - ' at Error (native)\n' + - ' at s (blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379:31:29146)\n' + - ' at Object.d [as add] (blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379:31:30039)\n' + - ' at blob:http%3A//localhost%3A8080/d4eefe0f-361a-4682-b217-76587d9f712a:15:10978\n' + - ' at blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379:1:6911\n' + - ' at n.fire (blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379:7:3019)\n' + - ' at n.handle (blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379:7:2863)', -}; - -export const CHROME_48_EVAL = { - message: 'message string', - name: 'Error', - stack: - 'Error: message string\n' + - 'at baz (eval at foo (eval at speak (http://localhost:8080/file.js:21:17)), :1:30)\n' + - 'at foo (eval at speak (http://localhost:8080/file.js:21:17), :2:96)\n' + - 'at eval (eval at speak (http://localhost:8080/file.js:21:17), :4:18)\n' + - 'at Object.speak (http://localhost:8080/file.js:21:17)\n' + - 'at http://localhost:8080/file.js:31:13\n', -}; - -export const PHANTOMJS_1_19 = { - name: 'foo', - message: 'bar', - stack: - 'Error: foo\n' + - ' at file:///path/to/file.js:878\n' + - ' at foo (http://path/to/file.js:4283)\n' + - ' at http://path/to/file.js:4287', -}; - -export const ANDROID_REACT_NATIVE = { - message: 'Error: test', - name: 'Error', - stack: - 'Error: test\n' + - 'at render(/home/username/sample-workspace/sampleapp.collect.react/src/components/GpsMonitorScene.js:78:24)\n' + - 'at _renderValidatedComponentWithoutOwnerOrContext(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js:1050:29)\n' + - 'at _renderValidatedComponent(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js:1075:15)\n' + - 'at renderedElement(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js:484:29)\n' + - 'at _currentElement(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js:346:40)\n' + - 'at child(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactReconciler.js:68:25)\n' + - 'at children(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactMultiChild.js:264:10)\n' + - 'at this(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/native/ReactNativeBaseComponent.js:74:41)\n', -}; - -export const ANDROID_REACT_NATIVE_PROD = { - message: 'Error: test', - name: 'Error', - stack: - 'value@index.android.bundle:12:1917\n' + - 'onPress@index.android.bundle:12:2336\n' + - 'touchableHandlePress@index.android.bundle:258:1497\n' + - '[native code]\n' + - '_performSideEffectsForTransition@index.android.bundle:252:8508\n' + - '[native code]\n' + - '_receiveSignal@index.android.bundle:252:7291\n' + - '[native code]\n' + - 'touchableHandleResponderRelease@index.android.bundle:252:4735\n' + - '[native code]\n' + - 'u@index.android.bundle:79:142\n' + - 'invokeGuardedCallback@index.android.bundle:79:459\n' + - 'invokeGuardedCallbackAndCatchFirstError@index.android.bundle:79:580\n' + - 'c@index.android.bundle:95:365\n' + - 'a@index.android.bundle:95:567\n' + - 'v@index.android.bundle:146:501\n' + - 'g@index.android.bundle:146:604\n' + - 'forEach@[native code]\n' + - 'i@index.android.bundle:149:80\n' + - 'processEventQueue@index.android.bundle:146:1432\n' + - 's@index.android.bundle:157:88\n' + - 'handleTopLevel@index.android.bundle:157:174\n' + - 'index.android.bundle:156:572\n' + - 'a@index.android.bundle:93:276\n' + - 'c@index.android.bundle:93:60\n' + - 'perform@index.android.bundle:177:596\n' + - 'batchedUpdates@index.android.bundle:188:464\n' + - 'i@index.android.bundle:176:358\n' + - 'i@index.android.bundle:93:90\n' + - 'u@index.android.bundle:93:150\n' + - '_receiveRootNodeIDEvent@index.android.bundle:156:544\n' + - 'receiveTouches@index.android.bundle:156:918\n' + - 'value@index.android.bundle:29:3016\n' + - 'index.android.bundle:29:955\n' + - 'value@index.android.bundle:29:2417\n' + - 'value@index.android.bundle:29:927\n' + - '[native code]', -}; - -export const ANDROID_REACT_NATIVE_HERMES = { - message: 'Error: lets throw!', - name: 'Error', - stack: - 'at onPress (address at index.android.bundle:1:452701)\n' + - 'at anonymous (address at index.android.bundle:1:224280)\n' + - 'at _performSideEffectsForTransition (address at index.android.bundle:1:230843)\n' + - 'at _receiveSignal (native)\n' + - 'at touchableHandleResponderRelease (native)\n' + - 'at onResponderRelease (native)\n' + - 'at apply (native)\n' + - 'at b (address at index.android.bundle:1:74037)\n' + - 'at apply (native)\n' + - 'at k (address at index.android.bundle:1:74094)\n' + - 'at apply (native)\n' + - 'at C (address at index.android.bundle:1:74126)\n' + - 'at N (address at index.android.bundle:1:74267)\n' + - 'at A (address at index.android.bundle:1:74709)\n' + - 'at forEach (native)\n' + - 'at z (address at index.android.bundle:1:74642)\n' + - 'at anonymous (address at index.android.bundle:1:77747)\n' + - 'at _e (address at index.android.bundle:1:127755)\n' + - 'at Ne (address at index.android.bundle:1:77238)\n' + - 'at Ue (address at index.android.bundle:1:77571)\n' + - 'at receiveTouches (address at index.android.bundle:1:122512)\n' + - 'at apply (native)\n' + - 'at value (address at index.android.bundle:1:33176)\n' + - 'at anonymous (address at index.android.bundle:1:31603)\n' + - 'at value (address at index.android.bundle:1:32776)\n' + - 'at value (address at index.android.bundle:1:31561)', -}; diff --git a/packages/browser/test/unit/tracekit/react-native.test.ts b/packages/browser/test/unit/tracekit/react-native.test.ts new file mode 100644 index 000000000000..eb8ed1d521ab --- /dev/null +++ b/packages/browser/test/unit/tracekit/react-native.test.ts @@ -0,0 +1,311 @@ +import { computeStackTrace } from '../../../src/tracekit'; + +describe('Tracekit - React Native Tests', () => { + it('should parse exceptions for react-native-v8', () => { + const REACT_NATIVE_V8_EXCEPTION = { + message: 'Manually triggered crash to test Sentry reporting', + name: 'Error', + stack: `Error: Manually triggered crash to test Sentry reporting + at Object.onPress(index.android.bundle:2342:3773) + at s.touchableHandlePress(index.android.bundle:214:2048) + at s._performSideEffectsForTransition(index.android.bundle:198:9608) + at s._receiveSignal(index.android.bundle:198:8309) + at s.touchableHandleResponderRelease(index.android.bundle:198:5615) + at Object.y(index.android.bundle:93:571) + at P(index.android.bundle:93:714)`, + }; + const stacktrace = computeStackTrace(REACT_NATIVE_V8_EXCEPTION); + + expect(stacktrace).toEqual({ + message: 'Manually triggered crash to test Sentry reporting', + name: 'Error', + stack: [ + { url: 'index.android.bundle', func: 'Object.onPress', line: 2342, column: 3773 }, + { url: 'index.android.bundle', func: 's.touchableHandlePress', line: 214, column: 2048 }, + { url: 'index.android.bundle', func: 's._performSideEffectsForTransition', line: 198, column: 9608 }, + { url: 'index.android.bundle', func: 's._receiveSignal', line: 198, column: 8309 }, + { url: 'index.android.bundle', func: 's.touchableHandleResponderRelease', line: 198, column: 5615 }, + { url: 'index.android.bundle', func: 'Object.y', line: 93, column: 571 }, + { url: 'index.android.bundle', func: 'P', line: 93, column: 714 }, + ], + }); + }); + + it('should parse exceptions for react-native Expo bundles', () => { + const REACT_NATIVE_EXPO_EXCEPTION = { + message: 'Test Error Expo', + name: 'Error', + stack: `onPress@/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3:595:658 + value@/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3:221:7656 + onResponderRelease@/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3:221:5666 + p@/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3:96:385 + forEach@[native code]`, + }; + const stacktrace = computeStackTrace(REACT_NATIVE_EXPO_EXCEPTION); + + expect(stacktrace).toEqual({ + message: 'Test Error Expo', + name: 'Error', + stack: [ + { + url: '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', + func: 'onPress', + line: 595, + column: 658, + }, + { + url: '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', + func: 'value', + line: 221, + column: 7656, + }, + { + url: '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', + func: 'onResponderRelease', + line: 221, + column: 5666, + }, + { + url: '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', + func: 'p', + line: 96, + column: 385, + }, + { url: '[native code]', func: 'forEach', line: null, column: null }, + ], + }); + }); + + it('should parse React Native errors on Android', () => { + const ANDROID_REACT_NATIVE = { + message: 'Error: test', + name: 'Error', + stack: + 'Error: test\n' + + 'at render(/home/username/sample-workspace/sampleapp.collect.react/src/components/GpsMonitorScene.js:78:24)\n' + + 'at _renderValidatedComponentWithoutOwnerOrContext(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js:1050:29)\n' + + 'at _renderValidatedComponent(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js:1075:15)\n' + + 'at renderedElement(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js:484:29)\n' + + 'at _currentElement(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js:346:40)\n' + + 'at child(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactReconciler.js:68:25)\n' + + 'at children(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactMultiChild.js:264:10)\n' + + 'at this(/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/native/ReactNativeBaseComponent.js:74:41)\n', + }; + + const stackFrames = computeStackTrace(ANDROID_REACT_NATIVE); + + expect(stackFrames).toEqual({ + message: 'Error: test', + name: 'Error', + stack: [ + { + url: '/home/username/sample-workspace/sampleapp.collect.react/src/components/GpsMonitorScene.js', + func: 'render', + line: 78, + column: 24, + }, + { + url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js', + func: '_renderValidatedComponentWithoutOwnerOrContext', + line: 1050, + column: 29, + }, + { + url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js', + func: '_renderValidatedComponent', + line: 1075, + column: 15, + }, + { + url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js', + func: 'renderedElement', + line: 484, + column: 29, + }, + { + url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js', + func: '_currentElement', + line: 346, + column: 40, + }, + { + url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactReconciler.js', + func: 'child', + line: 68, + column: 25, + }, + { + url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactMultiChild.js', + func: 'children', + line: 264, + column: 10, + }, + { + url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/native/ReactNativeBaseComponent.js', + func: 'this', + line: 74, + column: 41, + }, + ], + }); + }); + + it('should parse React Native errors on Android Production', () => { + const ANDROID_REACT_NATIVE_PROD = { + message: 'Error: test', + name: 'Error', + stack: + 'value@index.android.bundle:12:1917\n' + + 'onPress@index.android.bundle:12:2336\n' + + 'touchableHandlePress@index.android.bundle:258:1497\n' + + '[native code]\n' + + '_performSideEffectsForTransition@index.android.bundle:252:8508\n' + + '[native code]\n' + + '_receiveSignal@index.android.bundle:252:7291\n' + + '[native code]\n' + + 'touchableHandleResponderRelease@index.android.bundle:252:4735\n' + + '[native code]\n' + + 'u@index.android.bundle:79:142\n' + + 'invokeGuardedCallback@index.android.bundle:79:459\n' + + 'invokeGuardedCallbackAndCatchFirstError@index.android.bundle:79:580\n' + + 'c@index.android.bundle:95:365\n' + + 'a@index.android.bundle:95:567\n' + + 'v@index.android.bundle:146:501\n' + + 'g@index.android.bundle:146:604\n' + + 'forEach@[native code]\n' + + 'i@index.android.bundle:149:80\n' + + 'processEventQueue@index.android.bundle:146:1432\n' + + 's@index.android.bundle:157:88\n' + + 'handleTopLevel@index.android.bundle:157:174\n' + + 'index.android.bundle:156:572\n' + + 'a@index.android.bundle:93:276\n' + + 'c@index.android.bundle:93:60\n' + + 'perform@index.android.bundle:177:596\n' + + 'batchedUpdates@index.android.bundle:188:464\n' + + 'i@index.android.bundle:176:358\n' + + 'i@index.android.bundle:93:90\n' + + 'u@index.android.bundle:93:150\n' + + '_receiveRootNodeIDEvent@index.android.bundle:156:544\n' + + 'receiveTouches@index.android.bundle:156:918\n' + + 'value@index.android.bundle:29:3016\n' + + 'index.android.bundle:29:955\n' + + 'value@index.android.bundle:29:2417\n' + + 'value@index.android.bundle:29:927\n' + + '[native code]', + }; + + const stackFrames = computeStackTrace(ANDROID_REACT_NATIVE_PROD); + + expect(stackFrames).toEqual({ + message: 'Error: test', + name: 'Error', + stack: [ + { url: 'index.android.bundle', func: 'value', line: 12, column: 1917 }, + { url: 'index.android.bundle', func: 'onPress', line: 12, column: 2336 }, + { url: 'index.android.bundle', func: 'touchableHandlePress', line: 258, column: 1497 }, + { url: '[native code]', func: '?', line: null, column: null }, + { url: 'index.android.bundle', func: '_performSideEffectsForTransition', line: 252, column: 8508 }, + { url: '[native code]', func: '?', line: null, column: null }, + { url: 'index.android.bundle', func: '_receiveSignal', line: 252, column: 7291 }, + { url: '[native code]', func: '?', line: null, column: null }, + { url: 'index.android.bundle', func: 'touchableHandleResponderRelease', line: 252, column: 4735 }, + { url: '[native code]', func: '?', line: null, column: null }, + { url: 'index.android.bundle', func: 'u', line: 79, column: 142 }, + { url: 'index.android.bundle', func: 'invokeGuardedCallback', line: 79, column: 459 }, + { url: 'index.android.bundle', func: 'invokeGuardedCallbackAndCatchFirstError', line: 79, column: 580 }, + { url: 'index.android.bundle', func: 'c', line: 95, column: 365 }, + { url: 'index.android.bundle', func: 'a', line: 95, column: 567 }, + { url: 'index.android.bundle', func: 'v', line: 146, column: 501 }, + { url: 'index.android.bundle', func: 'g', line: 146, column: 604 }, + { url: '[native code]', func: 'forEach', line: null, column: null }, + { url: 'index.android.bundle', func: 'i', line: 149, column: 80 }, + { url: 'index.android.bundle', func: 'processEventQueue', line: 146, column: 1432 }, + { url: 'index.android.bundle', func: 's', line: 157, column: 88 }, + { url: 'index.android.bundle', func: 'handleTopLevel', line: 157, column: 174 }, + { url: 'index.android.bundle', func: '?', line: 156, column: 572 }, + { url: 'index.android.bundle', func: 'a', line: 93, column: 276 }, + { url: 'index.android.bundle', func: 'c', line: 93, column: 60 }, + { url: 'index.android.bundle', func: 'perform', line: 177, column: 596 }, + { url: 'index.android.bundle', func: 'batchedUpdates', line: 188, column: 464 }, + { url: 'index.android.bundle', func: 'i', line: 176, column: 358 }, + { url: 'index.android.bundle', func: 'i', line: 93, column: 90 }, + { url: 'index.android.bundle', func: 'u', line: 93, column: 150 }, + { url: 'index.android.bundle', func: '_receiveRootNodeIDEvent', line: 156, column: 544 }, + { url: 'index.android.bundle', func: 'receiveTouches', line: 156, column: 918 }, + { url: 'index.android.bundle', func: 'value', line: 29, column: 3016 }, + { url: 'index.android.bundle', func: '?', line: 29, column: 955 }, + { url: 'index.android.bundle', func: 'value', line: 29, column: 2417 }, + { url: 'index.android.bundle', func: 'value', line: 29, column: 927 }, + { url: '[native code]', func: '?', line: null, column: null }, + ], + }); + }); + + it('should parse React Native errors on Android Hermes', () => { + const ANDROID_REACT_NATIVE_HERMES = { + message: 'Error: lets throw!', + name: 'Error', + stack: + 'at onPress (address at index.android.bundle:1:452701)\n' + + 'at anonymous (address at index.android.bundle:1:224280)\n' + + 'at _performSideEffectsForTransition (address at index.android.bundle:1:230843)\n' + + 'at _receiveSignal (native)\n' + + 'at touchableHandleResponderRelease (native)\n' + + 'at onResponderRelease (native)\n' + + 'at apply (native)\n' + + 'at b (address at index.android.bundle:1:74037)\n' + + 'at apply (native)\n' + + 'at k (address at index.android.bundle:1:74094)\n' + + 'at apply (native)\n' + + 'at C (address at index.android.bundle:1:74126)\n' + + 'at N (address at index.android.bundle:1:74267)\n' + + 'at A (address at index.android.bundle:1:74709)\n' + + 'at forEach (native)\n' + + 'at z (address at index.android.bundle:1:74642)\n' + + 'at anonymous (address at index.android.bundle:1:77747)\n' + + 'at _e (address at index.android.bundle:1:127755)\n' + + 'at Ne (address at index.android.bundle:1:77238)\n' + + 'at Ue (address at index.android.bundle:1:77571)\n' + + 'at receiveTouches (address at index.android.bundle:1:122512)\n' + + 'at apply (native)\n' + + 'at value (address at index.android.bundle:1:33176)\n' + + 'at anonymous (address at index.android.bundle:1:31603)\n' + + 'at value (address at index.android.bundle:1:32776)\n' + + 'at value (address at index.android.bundle:1:31561)', + }; + const stackFrames = computeStackTrace(ANDROID_REACT_NATIVE_HERMES); + + expect(stackFrames).toEqual({ + message: 'Error: lets throw!', + name: 'Error', + stack: [ + { url: 'index.android.bundle', func: 'onPress', line: 1, column: 452701 }, + { url: 'index.android.bundle', func: 'anonymous', line: 1, column: 224280 }, + { url: 'index.android.bundle', func: '_performSideEffectsForTransition', line: 1, column: 230843 }, + { url: 'native', func: '_receiveSignal', line: null, column: null }, + { url: 'native', func: 'touchableHandleResponderRelease', line: null, column: null }, + { url: 'native', func: 'onResponderRelease', line: null, column: null }, + { url: 'native', func: 'apply', line: null, column: null }, + { url: 'index.android.bundle', func: 'b', line: 1, column: 74037 }, + { url: 'native', func: 'apply', line: null, column: null }, + { url: 'index.android.bundle', func: 'k', line: 1, column: 74094 }, + { url: 'native', func: 'apply', line: null, column: null }, + { url: 'index.android.bundle', func: 'C', line: 1, column: 74126 }, + { url: 'index.android.bundle', func: 'N', line: 1, column: 74267 }, + { url: 'index.android.bundle', func: 'A', line: 1, column: 74709 }, + { url: 'native', func: 'forEach', line: null, column: null }, + { url: 'index.android.bundle', func: 'z', line: 1, column: 74642 }, + { url: 'index.android.bundle', func: 'anonymous', line: 1, column: 77747 }, + { url: 'index.android.bundle', func: '_e', line: 1, column: 127755 }, + { url: 'index.android.bundle', func: 'Ne', line: 1, column: 77238 }, + { url: 'index.android.bundle', func: 'Ue', line: 1, column: 77571 }, + { url: 'index.android.bundle', func: 'receiveTouches', line: 1, column: 122512 }, + { url: 'native', func: 'apply', line: null, column: null }, + { url: 'index.android.bundle', func: 'value', line: 1, column: 33176 }, + { url: 'index.android.bundle', func: 'anonymous', line: 1, column: 31603 }, + { url: 'index.android.bundle', func: 'value', line: 1, column: 32776 }, + { url: 'index.android.bundle', func: 'value', line: 1, column: 31561 }, + ], + }); + }); +}); diff --git a/packages/browser/test/unit/tracekit/react.test.ts b/packages/browser/test/unit/tracekit/react.test.ts new file mode 100644 index 000000000000..7f648ff39593 --- /dev/null +++ b/packages/browser/test/unit/tracekit/react.test.ts @@ -0,0 +1,86 @@ +import { computeStackTrace } from '../../../src/tracekit'; + +describe('Tracekit - React Tests', () => { + it('should correctly parse Invariant Violation errors and use framesToPop to drop info message', () => { + const REACT_INVARIANT_VIOLATION_EXCEPTION = { + framesToPop: 1, + message: + 'Minified React error #31; visit https://reactjs.org/docs/error-decoder.html?invariant=31&args[]=object%20with%20keys%20%7B%7D&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings. ', + name: 'Invariant Violation', + stack: `Invariant Violation: Minified React error #31; visit https://reactjs.org/docs/error-decoder.html?invariant=31&args[]=object%20with%20keys%20%7B%7D&args[]= 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_INVARIANT_VIOLATION_EXCEPTION); + + expect(stacktrace).toEqual({ + message: + 'Minified React error #31; visit https://reactjs.org/docs/error-decoder.html?invariant=31&args[]=object%20with%20keys%20%7B%7D&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings. ', + name: 'Invariant Violation', + stack: [ + { url: 'http://localhost:5000/static/js/foo.chunk.js', func: '?', line: 1, column: 21738 }, + { url: 'http://localhost:5000/static/js/foo.chunk.js', func: 'a', line: 1, column: 21841 }, + { url: 'http://localhost:5000/static/js/foo.chunk.js', func: 'ho', line: 1, column: 68735 }, + { url: 'http://localhost:5000/', func: 'f', line: 1, column: 980 }, + ], + }); + }); + + 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).toEqual({ + 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: [ + { url: 'http://localhost:5000/static/js/foo.chunk.js', func: '?', line: 1, column: 21738 }, + { url: 'http://localhost:5000/static/js/foo.chunk.js', func: 'a', line: 1, column: 21841 }, + { url: 'http://localhost:5000/static/js/foo.chunk.js', func: 'ho', line: 1, column: 68735 }, + { url: 'http://localhost:5000/', func: 'f', line: 1, column: 980 }, + ], + }); + }); + + 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).toEqual({ + 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: [ + { url: 'http://localhost:5000/static/js/foo.chunk.js', func: '?', line: 1, column: 21738 }, + { url: 'http://localhost:5000/static/js/foo.chunk.js', func: 'a', line: 1, column: 21841 }, + { url: 'http://localhost:5000/static/js/foo.chunk.js', func: 'ho', line: 1, column: 68735 }, + { url: 'http://localhost:5000/', func: 'f', line: 1, column: 980 }, + ], + }); + }); +}); diff --git a/packages/browser/test/unit/tracekit/safari.test.ts b/packages/browser/test/unit/tracekit/safari.test.ts new file mode 100644 index 000000000000..55e9b4c7fb9c --- /dev/null +++ b/packages/browser/test/unit/tracekit/safari.test.ts @@ -0,0 +1,294 @@ +import { computeStackTrace } from '../../../src/tracekit'; + +describe('Tracekit - Safari Tests', () => { + it('should parse Safari 6 error', () => { + const SAFARI_6 = { + name: 'foo', + message: "'null' is not an object (evaluating 'x.undef')", + stack: + '@http://path/to/file.js:48\n' + + 'dumpException3@http://path/to/file.js:52\n' + + 'onclick@http://path/to/file.js:82\n' + + '[native code]', + line: 48, + sourceURL: 'http://path/to/file.js', + }; + + const stackFrames = computeStackTrace(SAFARI_6); + + expect(stackFrames).toEqual({ + message: "'null' is not an object (evaluating 'x.undef')", + name: 'foo', + stack: [ + { url: 'http://path/to/file.js', func: '?', line: 48, column: null }, + { url: 'http://path/to/file.js', func: 'dumpException3', line: 52, column: null }, + { url: 'http://path/to/file.js', func: 'onclick', line: 82, column: null }, + { url: '[native code]', func: '?', line: null, column: null }, + ], + }); + }); + + it('should parse Safari 7 error', () => { + const SAFARI_7 = { + message: "'null' is not an object (evaluating 'x.undef')", + name: 'TypeError', + stack: + 'http://path/to/file.js:48:22\n' + 'foo@http://path/to/file.js:52:15\n' + 'bar@http://path/to/file.js:108:107', + line: 47, + sourceURL: 'http://path/to/file.js', + }; + + const stackFrames = computeStackTrace(SAFARI_7); + + expect(stackFrames).toEqual({ + message: "'null' is not an object (evaluating 'x.undef')", + name: 'TypeError', + stack: [ + { url: 'http://path/to/file.js', func: '?', line: 48, column: 22 }, + { url: 'http://path/to/file.js', func: 'foo', line: 52, column: 15 }, + { url: 'http://path/to/file.js', func: 'bar', line: 108, column: 107 }, + ], + }); + }); + + it('should parse Safari 8 error', () => { + const SAFARI_8 = { + message: "null is not an object (evaluating 'x.undef')", + name: 'TypeError', + stack: + 'http://path/to/file.js:47:22\n' + 'foo@http://path/to/file.js:52:15\n' + 'bar@http://path/to/file.js:108:23', + line: 47, + column: 22, + sourceURL: 'http://path/to/file.js', + }; + + const stackFrames = computeStackTrace(SAFARI_8); + + expect(stackFrames).toEqual({ + message: "null is not an object (evaluating 'x.undef')", + name: 'TypeError', + stack: [ + { url: 'http://path/to/file.js', func: '?', line: 47, column: 22 }, + { url: 'http://path/to/file.js', func: 'foo', line: 52, column: 15 }, + { url: 'http://path/to/file.js', func: 'bar', line: 108, column: 23 }, + ], + }); + }); + + it('should parse Safari 8 eval error', () => { + // TODO: Take into account the line and column properties on the error object and use them for the first stack trace. + + const SAFARI_8_EVAL = { + message: "Can't find variable: getExceptionProps", + name: 'ReferenceError', + stack: + 'eval code\n' + + 'eval@[native code]\n' + + 'foo@http://path/to/file.js:58:21\n' + + 'bar@http://path/to/file.js:109:91', + line: 1, + column: 18, + }; + + const stackFrames = computeStackTrace(SAFARI_8_EVAL); + + expect(stackFrames).toEqual({ + message: "Can't find variable: getExceptionProps", + name: 'ReferenceError', + stack: [ + { url: '[native code]', func: 'eval', line: null, column: null }, + { url: 'http://path/to/file.js', func: 'foo', line: 58, column: 21 }, + { url: 'http://path/to/file.js', func: 'bar', line: 109, column: 91 }, + ], + }); + }); + + describe('Safari extensions', () => { + it('should parse exceptions for safari-extension', () => { + const SAFARI_EXTENSION_EXCEPTION = { + message: 'wat', + name: 'Error', + stack: `Error: wat + at ClipperError@safari-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js:223036:10) + at safari-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js:3313:26)`, + }; + + const stacktrace = computeStackTrace(SAFARI_EXTENSION_EXCEPTION); + + expect(stacktrace).toEqual({ + message: 'wat', + name: 'Error', + stack: [ + { + url: 'safari-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js', + func: 'ClipperError', + line: 223036, + column: 10, + }, + { + url: 'safari-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js', + func: '?', + line: 3313, + column: 26, + }, + ], + }); + }); + + it('should parse exceptions for safari-extension with frames-only stack', () => { + const SAFARI_EXTENSION_EXCEPTION = { + message: `undefined is not an object (evaluating 'e.groups.includes')`, + name: `TypeError`, + stack: `isClaimed@safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js:2:929865 + safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js:2:1588410 + promiseReactionJob@[native code]`, + }; + const stacktrace = computeStackTrace(SAFARI_EXTENSION_EXCEPTION); + + expect(stacktrace).toEqual({ + message: "undefined is not an object (evaluating 'e.groups.includes')", + name: 'TypeError', + stack: [ + { + url: 'safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js', + func: 'isClaimed', + line: 2, + column: 929865, + }, + { + url: 'safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js', + func: '?', + line: 2, + column: 1588410, + }, + { url: '[native code]', func: 'promiseReactionJob', line: null, column: null }, + ], + }); + }); + + it('should parse exceptions for safari-web-extension', () => { + const SAFARI_WEB_EXTENSION_EXCEPTION = { + message: 'wat', + name: 'Error', + stack: `Error: wat + at ClipperError@safari-web-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js:223036:10) + at safari-web-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js:3313:26)`, + }; + + const stacktrace = computeStackTrace(SAFARI_WEB_EXTENSION_EXCEPTION); + + expect(stacktrace).toEqual({ + message: 'wat', + name: 'Error', + stack: [ + { + url: 'safari-web-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js', + func: 'ClipperError', + line: 223036, + column: 10, + }, + { + url: 'safari-web-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js', + func: '?', + line: 3313, + column: 26, + }, + ], + }); + }); + + it('should parse exceptions for safari-web-extension with frames-only stack', () => { + const SAFARI_EXTENSION_EXCEPTION = { + message: `undefined is not an object (evaluating 'e.groups.includes')`, + name: `TypeError`, + stack: `p_@safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js:29:33314 + safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js:29:56027 + promiseReactionJob@[native code]`, + }; + const stacktrace = computeStackTrace(SAFARI_EXTENSION_EXCEPTION); + + expect(stacktrace).toEqual({ + message: "undefined is not an object (evaluating 'e.groups.includes')", + name: 'TypeError', + stack: [ + { + url: 'safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js', + func: 'p_', + line: 29, + column: 33314, + }, + { + url: 'safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js', + func: '?', + line: 29, + column: 56027, + }, + { url: '[native code]', func: 'promiseReactionJob', line: null, column: null }, + ], + }); + }); + }); + + it('should parse exceptions with native code frames in Safari 12', () => { + const SAFARI12_NATIVE_CODE_EXCEPTION = { + message: 'test', + name: 'Error', + stack: `fooIterator@http://localhost:5000/test:20:26 + map@[native code] + foo@http://localhost:5000/test:19:22 + global code@http://localhost:5000/test:24:10`, + }; + + const stacktrace = computeStackTrace(SAFARI12_NATIVE_CODE_EXCEPTION); + + expect(stacktrace).toEqual({ + message: 'test', + name: 'Error', + stack: [ + { url: 'http://localhost:5000/test', func: 'fooIterator', line: 20, column: 26 }, + { url: '[native code]', func: 'map', line: null, column: null }, + { url: 'http://localhost:5000/test', func: 'foo', line: 19, column: 22 }, + { url: 'http://localhost:5000/test', func: 'global code', line: 24, column: 10 }, + ], + }); + }); + + it('should parse exceptions with eval frames in Safari 12', () => { + const SAFARI12_EVAL_EXCEPTION = { + message: 'aha', + name: 'Error', + stack: `aha@http://localhost:5000/:19:22 + aha@[native code] + callAnotherThing@http://localhost:5000/:20:16 + callback@http://localhost:5000/:25:23 + http://localhost:5000/:34:25 + map@[native code] + test@http://localhost:5000/:33:26 + eval code + eval@[native code] + aha@http://localhost:5000/:39:9 + testMethod@http://localhost:5000/:44:10 + http://localhost:5000/:50:29`, + }; + + const stacktrace = computeStackTrace(SAFARI12_EVAL_EXCEPTION); + + expect(stacktrace).toEqual({ + message: 'aha', + name: 'Error', + stack: [ + { url: 'http://localhost:5000/', func: 'aha', line: 19, column: 22 }, + { url: '[native code]', func: 'aha', line: null, column: null }, + { url: 'http://localhost:5000/', func: 'callAnotherThing', line: 20, column: 16 }, + { url: 'http://localhost:5000/', func: 'callback', line: 25, column: 23 }, + { url: 'http://localhost:5000/', func: '?', line: 34, column: 25 }, + { url: '[native code]', func: 'map', line: null, column: null }, + { url: 'http://localhost:5000/', func: 'test', line: 33, column: 26 }, + { url: '[native code]', func: 'eval', line: null, column: null }, + { url: 'http://localhost:5000/', func: 'aha', line: 39, column: 9 }, + { url: 'http://localhost:5000/', func: 'testMethod', line: 44, column: 10 }, + { url: 'http://localhost:5000/', func: '?', line: 50, column: 29 }, + ], + }); + }); +}); From 55634711fce81200806d4c262d5fbec209ea8e63 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Tue, 8 Feb 2022 01:13:00 +0000 Subject: [PATCH 2/5] Remove TraceKitStackFrame --- packages/browser/src/parsers.ts | 24 +- packages/browser/src/tracekit.ts | 99 +++---- packages/browser/test/unit/parsers.test.ts | 26 +- .../test/unit/tracekit/chromium.test.ts | 184 +++++++------ .../test/unit/tracekit/firefox.test.ts | 98 ++++--- .../browser/test/unit/tracekit/ie.test.ts | 18 +- .../browser/test/unit/tracekit/misc.test.ts | 6 +- .../browser/test/unit/tracekit/opera.test.ts | 45 ++-- .../test/unit/tracekit/react-native.test.ts | 254 ++++++++++-------- .../browser/test/unit/tracekit/react.test.ts | 24 +- .../browser/test/unit/tracekit/safari.test.ts | 124 ++++----- 11 files changed, 465 insertions(+), 437 deletions(-) diff --git a/packages/browser/src/parsers.ts b/packages/browser/src/parsers.ts index 69a7ee755b7a..db9f8b532317 100644 --- a/packages/browser/src/parsers.ts +++ b/packages/browser/src/parsers.ts @@ -1,7 +1,7 @@ import { Event, Exception, StackFrame } from '@sentry/types'; import { extractExceptionKeysForMessage, isEvent, normalizeToSize } from '@sentry/utils'; -import { computeStackTrace, StackFrame as TraceKitStackFrame, StackTrace as TraceKitStackTrace } from './tracekit'; +import { computeStackTrace, StackTrace as TraceKitStackTrace } from './tracekit'; const STACKTRACE_LIMIT = 50; @@ -80,15 +80,15 @@ export function eventFromStacktrace(stacktrace: TraceKitStackTrace): Event { /** * @hidden */ -export function prepareFramesForEvent(stack: TraceKitStackFrame[]): StackFrame[] { +export function prepareFramesForEvent(stack: StackFrame[]): StackFrame[] { if (!stack || !stack.length) { return []; } let localStack = stack; - const firstFrameFunction = localStack[0].func || ''; - const lastFrameFunction = localStack[localStack.length - 1].func || ''; + const firstFrameFunction = localStack[0].function || ''; + const lastFrameFunction = localStack[localStack.length - 1].function || ''; // If stack starts with one of our API calls, remove it (starts, meaning it's the top of the stack - aka last call) if (firstFrameFunction.indexOf('captureMessage') !== -1 || firstFrameFunction.indexOf('captureException') !== -1) { @@ -103,14 +103,12 @@ export function prepareFramesForEvent(stack: TraceKitStackFrame[]): StackFrame[] // The frame where the crash happened, should be the last entry in the array return localStack .slice(0, STACKTRACE_LIMIT) - .map( - (frame: TraceKitStackFrame): StackFrame => ({ - colno: frame.column === null ? undefined : frame.column, - filename: frame.url || localStack[0].url, - function: frame.func || '?', - in_app: true, - lineno: frame.line === null ? undefined : frame.line, - }), - ) + .map(frame => ({ + colno: frame.colno, + filename: frame.filename || localStack[0].filename, + function: frame.function || '?', + in_app: true, + lineno: frame.lineno, + })) .reverse(); } diff --git a/packages/browser/src/tracekit.ts b/packages/browser/src/tracekit.ts index e91dc37ddc58..0c59b8605821 100644 --- a/packages/browser/src/tracekit.ts +++ b/packages/browser/src/tracekit.ts @@ -1,3 +1,5 @@ +import { StackFrame } from '@sentry/types'; + /** * This was originally forked from https://github.com/occ/TraceKit, but has since been * largely modified and is now maintained as part of Sentry JS SDK. @@ -5,23 +7,6 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access, max-lines */ -/** - * An object representing a single stack frame. - * {Object} StackFrame - * {string} url The JavaScript or HTML file URL. - * {string} func The function name, or empty for anonymous functions (if guessing did not work). - * {string[]?} args The arguments passed to the function, if known. - * {number=} line The line number, if known. - * {number=} column The column number, if known. - * {string[]} context An array of source code lines; the middle element corresponds to the correct line#. - */ -export interface StackFrame { - url: string; - func: string; - line: number | null; - column: number | null; -} - /** * An object representing a JavaScript stack trace. * {Object} StackTrace @@ -32,9 +17,7 @@ export interface StackFrame { export interface StackTrace { name: string; message: string; - mechanism?: string; stack: StackFrame[]; - failed?: boolean; } // global reference to slice @@ -56,9 +39,8 @@ const chromeEval = /\((\S*)(?::(\d+))(?::(\d+))\)/; const reactMinifiedRegexp = /Minified React error #\d+;/i; /** JSDoc */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types -export function computeStackTrace(ex: any): StackTrace { - let stack = null; +export function computeStackTrace(ex: Error & { framesToPop?: number }): StackTrace { + let stack; let popSize = 0; if (ex) { @@ -94,13 +76,12 @@ export function computeStackTrace(ex: any): StackTrace { message: extractMessage(ex), name: ex && ex.name, stack: [], - failed: true, }; } /** JSDoc */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any, complexity -function computeStackTraceFromStackProp(ex: any): StackTrace | null { +// eslint-disable-next-line complexity +function computeStackTraceFromStackProp(ex: Error): StackTrace | null { if (!ex || !ex.stack) { return null; } @@ -110,7 +91,7 @@ function computeStackTraceFromStackProp(ex: any): StackTrace | null { let isEval; let submatch; let parts; - let element; + let element: StackFrame | undefined = undefined; for (const line of lines) { if ((parts = chrome.exec(line))) { @@ -124,20 +105,20 @@ function computeStackTraceFromStackProp(ex: any): StackTrace | null { // Kamil: One more hack won't hurt us right? Understanding and adding more rules on top of these regexps right now // would be way too time consuming. (TODO: Rewrite whole RegExp to be more readable) - const [func, url] = extractSafariExtensionDetails(parts[1] || UNKNOWN_FUNCTION, parts[2]); + const [func, filename] = extractSafariExtensionDetails(parts[1] || UNKNOWN_FUNCTION, parts[2]); element = { - url, - func, - line: parts[3] ? +parts[3] : null, - column: parts[4] ? +parts[4] : null, + filename, + function: func, + lineno: parts[3] ? +parts[3] : undefined, + colno: parts[4] ? +parts[4] : undefined, }; } else if ((parts = winjs.exec(line))) { element = { - url: parts[2], - func: parts[1] || UNKNOWN_FUNCTION, - line: +parts[3], - column: parts[4] ? +parts[4] : null, + filename: parts[2], + function: parts[1] || UNKNOWN_FUNCTION, + lineno: +parts[3], + colno: parts[4] ? +parts[4] : undefined, }; } else if ((parts = gecko.exec(line))) { isEval = parts[3] && parts[3].indexOf(' > eval') > -1; @@ -149,15 +130,15 @@ function computeStackTraceFromStackProp(ex: any): StackTrace | null { parts[5] = ''; // no column when eval } - let url = parts[3]; + let filename = parts[3]; let func = parts[1] || UNKNOWN_FUNCTION; - [func, url] = extractSafariExtensionDetails(func, url); + [func, filename] = extractSafariExtensionDetails(func, filename); element = { - url, - func, - line: parts[4] ? +parts[4] : null, - column: parts[5] ? +parts[5] : null, + filename, + function: func, + lineno: parts[4] ? +parts[4] : undefined, + colno: parts[5] ? +parts[5] : undefined, }; } else { continue; @@ -178,8 +159,7 @@ function computeStackTraceFromStackProp(ex: any): StackTrace | null { } /** JSDoc */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function computeStackTraceFromStacktraceProp(ex: any): StackTrace | null { +function computeStackTraceFromStacktraceProp(ex: Error & { stacktrace?: string }): StackTrace | null { if (!ex || !ex.stacktrace) { return null; } @@ -194,28 +174,25 @@ function computeStackTraceFromStacktraceProp(ex: any): StackTrace | null { const stack = []; let parts; - for (let line = 0; line < lines.length; line += 2) { - let element = null; - if ((parts = opera10Regex.exec(lines[line]))) { + for (const line of lines) { + let element: StackFrame | undefined = undefined; + + if ((parts = opera10Regex.exec(line))) { element = { - url: parts[2], - func: parts[3], - line: +parts[1], - column: null, + filename: parts[2], + function: parts[3] || UNKNOWN_FUNCTION, + lineno: +parts[1], }; - } else if ((parts = opera11Regex.exec(lines[line]))) { + } else if ((parts = opera11Regex.exec(line))) { element = { - url: parts[5], - func: parts[3] || parts[4], - line: +parts[1], - column: +parts[2], + filename: parts[5], + function: parts[3] || parts[4] || UNKNOWN_FUNCTION, + lineno: +parts[1], + colno: +parts[2], }; } if (element) { - if (!element.func && element.line) { - element.func = UNKNOWN_FUNCTION; - } stack.push(element); } } @@ -251,16 +228,16 @@ function computeStackTraceFromStacktraceProp(ex: any): StackTrace | null { * Unfortunatelly "just" changing RegExp is too complicated now and making it pass all tests * and fix this case seems like an impossible, or at least way too time-consuming task. */ -const extractSafariExtensionDetails = (func: string, url: string): [string, string] => { +const extractSafariExtensionDetails = (func: string, filename: string): [string, string] => { const isSafariExtension = func.indexOf('safari-extension') !== -1; const isSafariWebExtension = func.indexOf('safari-web-extension') !== -1; return isSafariExtension || isSafariWebExtension ? [ func.indexOf('@') !== -1 ? func.split('@')[0] : UNKNOWN_FUNCTION, - isSafariExtension ? `safari-extension:${url}` : `safari-web-extension:${url}`, + isSafariExtension ? `safari-extension:${filename}` : `safari-web-extension:${filename}`, ] - : [func, url]; + : [func, filename]; }; /** Remove N number of frames from the stack */ diff --git a/packages/browser/test/unit/parsers.test.ts b/packages/browser/test/unit/parsers.test.ts index 675ac19e62e7..475d720fd3d1 100644 --- a/packages/browser/test/unit/parsers.test.ts +++ b/packages/browser/test/unit/parsers.test.ts @@ -5,9 +5,9 @@ describe('Parsers', () => { describe('removed top frame if its internally reserved word (public API)', () => { it('reserved captureException', () => { const stack = [ - { context: ['x'], column: 1, line: 4, url: 'anything.js', func: 'captureException', args: [] }, - { context: ['x'], column: 1, line: 3, url: 'anything.js', func: 'foo', args: [] }, - { context: ['x'], column: 1, line: 2, url: 'anything.js', func: 'bar', args: [] }, + { colno: 1, lineno: 4, filename: 'anything.js', function: 'captureException' }, + { colno: 1, lineno: 3, filename: 'anything.js', function: 'foo' }, + { colno: 1, lineno: 2, filename: 'anything.js', function: 'bar' }, ]; // Should remove `captureException` as its a name considered "internal" @@ -20,9 +20,9 @@ describe('Parsers', () => { it('reserved captureMessage', () => { const stack = [ - { context: ['x'], column: 1, line: 4, url: 'anything.js', func: 'captureMessage', args: [] }, - { context: ['x'], column: 1, line: 3, url: 'anything.js', func: 'foo', args: [] }, - { context: ['x'], column: 1, line: 2, url: 'anything.js', func: 'bar', args: [] }, + { colno: 1, lineno: 4, filename: 'anything.js', function: 'captureMessage' }, + { colno: 1, lineno: 3, filename: 'anything.js', function: 'foo' }, + { colno: 1, lineno: 2, filename: 'anything.js', function: 'bar' }, ]; // Should remove `captureMessage` as its a name considered "internal" @@ -37,9 +37,9 @@ describe('Parsers', () => { describe('removed bottom frame if its internally reserved word (internal API)', () => { it('reserved sentryWrapped', () => { const stack = [ - { context: ['x'], column: 1, line: 3, url: 'anything.js', func: 'foo', args: [] }, - { context: ['x'], column: 1, line: 2, url: 'anything.js', func: 'bar', args: [] }, - { context: ['x'], column: 1, line: 1, url: 'anything.js', func: 'sentryWrapped', args: [] }, + { colno: 1, lineno: 3, filename: 'anything.js', function: 'foo' }, + { colno: 1, lineno: 2, filename: 'anything.js', function: 'bar' }, + { colno: 1, lineno: 1, filename: 'anything.js', function: 'sentryWrapped' }, ]; // Should remove `sentryWrapped` as its a name considered "internal" @@ -53,10 +53,10 @@ describe('Parsers', () => { it('removed top and bottom frame if they are internally reserved words', () => { const stack = [ - { context: ['x'], column: 1, line: 4, url: 'anything.js', func: 'captureMessage', args: [] }, - { context: ['x'], column: 1, line: 3, url: 'anything.js', func: 'foo', args: [] }, - { context: ['x'], column: 1, line: 2, url: 'anything.js', func: 'bar', args: [] }, - { context: ['x'], column: 1, line: 1, url: 'anything.js', func: 'sentryWrapped', args: [] }, + { colno: 1, lineno: 4, filename: 'anything.js', function: 'captureMessage' }, + { colno: 1, lineno: 3, filename: 'anything.js', function: 'foo' }, + { colno: 1, lineno: 2, filename: 'anything.js', function: 'bar' }, + { colno: 1, lineno: 1, filename: 'anything.js', function: 'sentryWrapped' }, ]; // Should remove `captureMessage` and `sentryWrapped` as its a name considered "internal" diff --git a/packages/browser/test/unit/tracekit/chromium.test.ts b/packages/browser/test/unit/tracekit/chromium.test.ts index 65555c4656b6..5d503c33d14a 100644 --- a/packages/browser/test/unit/tracekit/chromium.test.ts +++ b/packages/browser/test/unit/tracekit/chromium.test.ts @@ -8,7 +8,7 @@ describe('Tracekit - Chrome Tests', () => { expect(stackFrames).toEqual({ message: 'foo', name: 'bar', - stack: [{ url: 'native', func: 'Array.forEach', line: null, column: null }], + stack: [{ filename: 'native', function: 'Array.forEach', lineno: undefined, colno: undefined }], }); }); @@ -31,10 +31,10 @@ describe('Tracekit - Chrome Tests', () => { message: "Object # has no method 'undef'", name: 'foo', stack: [ - { url: 'http://path/to/file.js', func: 'bar', line: 13, column: 17 }, - { url: 'http://path/to/file.js', func: 'bar', line: 16, column: 5 }, - { url: 'http://path/to/file.js', func: 'foo', line: 20, column: 5 }, - { url: 'http://path/to/file.js', func: '?', line: 24, column: 4 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 13, colno: 17 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 16, colno: 5 }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 20, colno: 5 }, + { filename: 'http://path/to/file.js', function: '?', lineno: 24, colno: 4 }, ], }); }); @@ -56,13 +56,13 @@ describe('Tracekit - Chrome Tests', () => { message: 'Default error', name: 'Error', stack: [ - { url: 'http://localhost:8080/file.js', func: 'dumpExceptionError', line: 41, column: 27 }, - { url: 'http://localhost:8080/file.js', func: 'HTMLButtonElement.onclick', line: 107, column: 146 }, + { filename: 'http://localhost:8080/file.js', function: 'dumpExceptionError', lineno: 41, colno: 27 }, + { filename: 'http://localhost:8080/file.js', function: 'HTMLButtonElement.onclick', lineno: 107, colno: 146 }, { - url: 'http://localhost:8080/file.js', - func: 'I.e.fn.(anonymous function) [as index]', - line: 10, - column: 3651, + filename: 'http://localhost:8080/file.js', + function: 'I.e.fn.(anonymous function) [as index]', + lineno: 10, + colno: 3651, }, ], }); @@ -87,19 +87,29 @@ describe('Tracekit - Chrome Tests', () => { message: "Cannot read property 'error' of undefined", name: 'TypeError', stack: [ - { url: 'webpack:///./src/components/test/test.jsx?', func: 'TESTTESTTEST.eval', line: 295, column: 108 }, - { url: 'webpack:///./src/components/test/test.jsx?', func: 'TESTTESTTEST.render', line: 272, column: 32 }, { - url: 'webpack:///./~/react-transform-catch-errors/lib/index.js?', - func: 'TESTTESTTEST.tryRender', - line: 34, - column: 31, + filename: 'webpack:///./src/components/test/test.jsx?', + function: 'TESTTESTTEST.eval', + lineno: 295, + colno: 108, }, { - url: 'webpack:///./~/react-proxy/modules/createPrototypeProxy.js?', - func: 'TESTTESTTEST.proxiedMethod', - line: 44, - column: 30, + filename: 'webpack:///./src/components/test/test.jsx?', + function: 'TESTTESTTEST.render', + lineno: 272, + colno: 32, + }, + { + filename: 'webpack:///./~/react-transform-catch-errors/lib/index.js?', + function: 'TESTTESTTEST.tryRender', + lineno: 34, + colno: 31, + }, + { + filename: 'webpack:///./~/react-proxy/modules/createPrototypeProxy.js?', + function: 'TESTTESTTEST.proxiedMethod', + lineno: 44, + colno: 30, }, ], }); @@ -124,11 +134,11 @@ describe('Tracekit - Chrome Tests', () => { message: 'message string', name: 'Error', stack: [ - { url: 'http://localhost:8080/file.js', func: 'baz', line: 21, column: 17 }, - { url: 'http://localhost:8080/file.js', func: 'foo', line: 21, column: 17 }, - { url: 'http://localhost:8080/file.js', func: 'eval', line: 21, column: 17 }, - { url: 'http://localhost:8080/file.js', func: 'Object.speak', line: 21, column: 17 }, - { url: 'http://localhost:8080/file.js', func: '?', line: 31, column: 13 }, + { filename: 'http://localhost:8080/file.js', function: 'baz', lineno: 21, colno: 17 }, + { filename: 'http://localhost:8080/file.js', function: 'foo', lineno: 21, colno: 17 }, + { filename: 'http://localhost:8080/file.js', function: 'eval', lineno: 21, colno: 17 }, + { filename: 'http://localhost:8080/file.js', function: 'Object.speak', lineno: 21, colno: 17 }, + { filename: 'http://localhost:8080/file.js', function: '?', lineno: 31, colno: 13 }, ], }); }); @@ -154,42 +164,42 @@ describe('Tracekit - Chrome Tests', () => { message: 'Error: test', name: 'Error', stack: [ - { url: 'native', func: 'Error', line: null, column: null }, + { filename: 'native', function: 'Error', lineno: undefined, colno: undefined }, { - url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', - func: 's', - line: 31, - column: 29146, + filename: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', + function: 's', + lineno: 31, + colno: 29146, }, { - url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', - func: 'Object.d [as add]', - line: 31, - column: 30039, + filename: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', + function: 'Object.d [as add]', + lineno: 31, + colno: 30039, }, { - url: 'blob:http%3A//localhost%3A8080/d4eefe0f-361a-4682-b217-76587d9f712a', - func: '?', - line: 15, - column: 10978, + filename: 'blob:http%3A//localhost%3A8080/d4eefe0f-361a-4682-b217-76587d9f712a', + function: '?', + lineno: 15, + colno: 10978, }, { - url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', - func: '?', - line: 1, - column: 6911, + filename: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', + function: '?', + lineno: 1, + colno: 6911, }, { - url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', - func: 'n.fire', - line: 7, - column: 3019, + filename: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', + function: 'n.fire', + lineno: 7, + colno: 3019, }, { - url: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', - func: 'n.handle', - line: 7, - column: 2863, + filename: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', + function: 'n.handle', + lineno: 7, + colno: 2863, }, ], }); @@ -209,7 +219,12 @@ describe('Tracekit - Chrome Tests', () => { message: 'message string', name: 'Error', stack: [ - { url: 'examplescheme://examplehost/cd351f7250857e22ceaa.worker.js', func: '?', line: 70179, column: 15 }, + { + filename: 'examplescheme://examplehost/cd351f7250857e22ceaa.worker.js', + function: '?', + lineno: 70179, + colno: 15, + }, ], }); }); @@ -231,10 +246,10 @@ describe('Tracekit - Chrome Tests', () => { message: 'test', name: 'Error', stack: [ - { url: 'http://localhost:5000/test', func: 'fooIterator', line: 20, column: 17 }, - { url: '', func: 'Array.map', line: null, column: null }, - { url: 'http://localhost:5000/test', func: 'foo', line: 19, column: 19 }, - { url: 'http://localhost:5000/test', func: '?', line: 24, column: 7 }, + { filename: 'http://localhost:5000/test', function: 'fooIterator', lineno: 20, colno: 17 }, + { filename: '', function: 'Array.map', lineno: undefined, colno: undefined }, + { filename: 'http://localhost:5000/test', function: 'foo', lineno: 19, colno: 19 }, + { filename: 'http://localhost:5000/test', function: '?', lineno: 24, colno: 7 }, ], }); }); @@ -262,16 +277,16 @@ describe('Tracekit - Chrome Tests', () => { message: 'bad', name: 'Error', stack: [ - { url: 'http://localhost:5000/', func: 'Object.aha', line: 19, column: 13 }, - { url: 'http://localhost:5000/', func: 'callAnotherThing', line: 20, column: 16 }, - { url: 'http://localhost:5000/', func: 'Object.callback', line: 25, column: 7 }, - { url: 'http://localhost:5000/', func: '?', line: 34, column: 17 }, - { url: '', func: 'Array.map', line: null, column: null }, - { url: 'http://localhost:5000/', func: 'test', line: 33, column: 23 }, - { url: 'http://localhost:5000/', func: 'eval', line: 37, column: 5 }, - { url: 'http://localhost:5000/', func: 'aha', line: 39, column: 5 }, - { url: 'http://localhost:5000/', func: 'Foo.testMethod', line: 44, column: 7 }, - { url: 'http://localhost:5000/', func: '?', line: 50, column: 19 }, + { filename: 'http://localhost:5000/', function: 'Object.aha', lineno: 19, colno: 13 }, + { filename: 'http://localhost:5000/', function: 'callAnotherThing', lineno: 20, colno: 16 }, + { filename: 'http://localhost:5000/', function: 'Object.callback', lineno: 25, colno: 7 }, + { filename: 'http://localhost:5000/', function: '?', lineno: 34, colno: 17 }, + { filename: '', function: 'Array.map', lineno: undefined, colno: undefined }, + { filename: 'http://localhost:5000/', function: 'test', lineno: 33, colno: 23 }, + { filename: 'http://localhost:5000/', function: 'eval', lineno: 37, colno: 5 }, + { filename: 'http://localhost:5000/', function: 'aha', lineno: 39, colno: 5 }, + { filename: 'http://localhost:5000/', function: 'Foo.testMethod', lineno: 44, colno: 7 }, + { filename: 'http://localhost:5000/', function: '?', lineno: 50, colno: 19 }, ], }); }); @@ -293,10 +308,10 @@ describe('Tracekit - Chrome Tests', () => { message: 'test', name: 'Error', stack: [ - { url: 'http://localhost:5000/test', func: 'fooIterator', line: 20, column: 11 }, - { url: 'native code', func: 'Array.prototype.map', line: null, column: null }, - { url: 'http://localhost:5000/test', func: 'foo', line: 19, column: 9 }, - { url: 'http://localhost:5000/test', func: 'Global code', line: 24, column: 7 }, + { filename: 'http://localhost:5000/test', function: 'fooIterator', lineno: 20, colno: 11 }, + { filename: 'native code', function: 'Array.prototype.map', lineno: undefined, colno: undefined }, + { filename: 'http://localhost:5000/test', function: 'foo', lineno: 19, colno: 9 }, + { filename: 'http://localhost:5000/test', function: 'Global code', lineno: 24, colno: 7 }, ], }); }); @@ -324,16 +339,16 @@ describe('Tracekit - Chrome Tests', () => { message: 'aha', name: 'Error', stack: [ - { url: 'http://localhost:5000/', func: 'aha', line: 19, column: 7 }, - { url: 'http://localhost:5000/', func: 'callAnotherThing', line: 18, column: 6 }, - { url: 'http://localhost:5000/', func: 'callback', line: 25, column: 7 }, - { url: 'http://localhost:5000/', func: 'Anonymous function', line: 34, column: 7 }, - { url: 'native code', func: 'Array.prototype.map', line: null, column: null }, - { url: 'http://localhost:5000/', func: 'test', line: 33, column: 5 }, - { url: 'eval code', func: 'eval code', line: 1, column: 1 }, - { url: 'http://localhost:5000/', func: 'aha', line: 39, column: 5 }, - { url: 'http://localhost:5000/', func: 'Foo.prototype.testMethod', line: 44, column: 7 }, - { url: 'http://localhost:5000/', func: 'Anonymous function', line: 50, column: 8 }, + { filename: 'http://localhost:5000/', function: 'aha', lineno: 19, colno: 7 }, + { filename: 'http://localhost:5000/', function: 'callAnotherThing', lineno: 18, colno: 6 }, + { filename: 'http://localhost:5000/', function: 'callback', lineno: 25, colno: 7 }, + { filename: 'http://localhost:5000/', function: 'Anonymous function', lineno: 34, colno: 7 }, + { filename: 'native code', function: 'Array.prototype.map', lineno: undefined, colno: undefined }, + { filename: 'http://localhost:5000/', function: 'test', lineno: 33, colno: 5 }, + { filename: 'eval code', function: 'eval code', lineno: 1, colno: 1 }, + { filename: 'http://localhost:5000/', function: 'aha', lineno: 39, colno: 5 }, + { filename: 'http://localhost:5000/', function: 'Foo.prototype.testMethod', lineno: 44, colno: 7 }, + { filename: 'http://localhost:5000/', function: 'Anonymous function', lineno: 50, colno: 8 }, ], }); }); @@ -351,7 +366,14 @@ describe('Tracekit - Chrome Tests', () => { expect(stacktrace).toEqual({ message: "Cannot read property 'error' of undefined", name: 'TypeError', - stack: [{ url: 'C:\\Users\\user\\path\\to\\file.js', func: 'TESTTESTTEST.someMethod', line: 295, column: 108 }], + stack: [ + { + filename: 'C:\\Users\\user\\path\\to\\file.js', + function: 'TESTTESTTEST.someMethod', + lineno: 295, + colno: 108, + }, + ], }); }); }); diff --git a/packages/browser/test/unit/tracekit/firefox.test.ts b/packages/browser/test/unit/tracekit/firefox.test.ts index 03414c66da3a..8f238431e92f 100644 --- a/packages/browser/test/unit/tracekit/firefox.test.ts +++ b/packages/browser/test/unit/tracekit/firefox.test.ts @@ -24,13 +24,18 @@ describe('Tracekit - Firefox Tests', () => { message: 'this.undef is not a function', name: 'TypeError', stack: [ - { url: 'http://127.0.0.1:8000/js/stacktrace.js', func: '?', line: 44, column: null }, - { url: 'http://127.0.0.1:8000/js/stacktrace.js', func: '?', line: 31, column: null }, - { url: 'http://127.0.0.1:8000/js/stacktrace.js', func: 'printStackTrace', line: 18, column: null }, - { url: 'http://127.0.0.1:8000/js/file.js', func: 'bar', line: 13, column: null }, - { url: 'http://127.0.0.1:8000/js/file.js', func: 'bar', line: 16, column: null }, - { url: 'http://127.0.0.1:8000/js/file.js', func: 'foo', line: 20, column: null }, - { url: 'http://127.0.0.1:8000/js/file.js', func: '?', line: 24, column: null }, + { filename: 'http://127.0.0.1:8000/js/stacktrace.js', function: '?', lineno: 44, colno: undefined }, + { filename: 'http://127.0.0.1:8000/js/stacktrace.js', function: '?', lineno: 31, colno: undefined }, + { + filename: 'http://127.0.0.1:8000/js/stacktrace.js', + function: 'printStackTrace', + lineno: 18, + colno: undefined, + }, + { filename: 'http://127.0.0.1:8000/js/file.js', function: 'bar', lineno: 13, colno: undefined }, + { filename: 'http://127.0.0.1:8000/js/file.js', function: 'bar', lineno: 16, colno: undefined }, + { filename: 'http://127.0.0.1:8000/js/file.js', function: 'foo', lineno: 20, colno: undefined }, + { filename: 'http://127.0.0.1:8000/js/file.js', function: '?', lineno: 24, colno: undefined }, ], }); }); @@ -58,13 +63,13 @@ describe('Tracekit - Firefox Tests', () => { message: 'bar', name: 'foo', stack: [ - { url: 'file:///G:/js/stacktrace.js', func: '?', line: 44, column: null }, - { url: 'file:///G:/js/stacktrace.js', func: '?', line: 31, column: null }, - { url: 'file:///G:/js/stacktrace.js', func: 'printStackTrace', line: 18, column: null }, - { url: 'file:///G:/js/file.js', func: 'bar', line: 13, column: null }, - { url: 'file:///G:/js/file.js', func: 'bar', line: 16, column: null }, - { url: 'file:///G:/js/file.js', func: 'foo', line: 20, column: null }, - { url: 'file:///G:/js/file.js', func: '?', line: 24, column: null }, + { filename: 'file:///G:/js/stacktrace.js', function: '?', lineno: 44, colno: undefined }, + { filename: 'file:///G:/js/stacktrace.js', function: '?', lineno: 31, colno: undefined }, + { filename: 'file:///G:/js/stacktrace.js', function: 'printStackTrace', lineno: 18, colno: undefined }, + { filename: 'file:///G:/js/file.js', function: 'bar', lineno: 13, colno: undefined }, + { filename: 'file:///G:/js/file.js', function: 'bar', lineno: 16, colno: undefined }, + { filename: 'file:///G:/js/file.js', function: 'foo', lineno: 20, colno: undefined }, + { filename: 'file:///G:/js/file.js', function: '?', lineno: 24, colno: undefined }, ], }); }); @@ -88,9 +93,9 @@ describe('Tracekit - Firefox Tests', () => { message: 'x is null', name: 'foo', stack: [ - { url: 'http://path/to/file.js', func: '?', line: 48, column: null }, - { url: 'http://path/to/file.js', func: 'dumpException3', line: 52, column: null }, - { url: 'http://path/to/file.js', func: 'onclick', line: 1, column: null }, + { filename: 'http://path/to/file.js', function: '?', lineno: 48, colno: undefined }, + { filename: 'http://path/to/file.js', function: 'dumpException3', lineno: 52, colno: undefined }, + { filename: 'http://path/to/file.js', function: 'onclick', lineno: 1, colno: undefined }, ], }); }); @@ -115,9 +120,9 @@ describe('Tracekit - Firefox Tests', () => { message: 'Default error', name: 'Error', stack: [ - { url: 'http://path/to/file.js', func: 'foo', line: 41, column: 13 }, - { url: 'http://path/to/file.js', func: 'bar', line: 1, column: 1 }, - { url: 'http://path/to/file.js', func: '.plugin/e.fn[c]/<', line: 1, column: 1 }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 41, colno: 13 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 1, colno: 1 }, + { filename: 'http://path/to/file.js', function: '.plugin/e.fn[c]/<', lineno: 1, colno: 1 }, ], }); }); @@ -148,10 +153,10 @@ describe('Tracekit - Firefox Tests', () => { message: 'No error message', name: 'NS_ERROR_FAILURE', stack: [ - { url: 'http://path/to/file.js', func: '[2] { message: 'this.props.raw[this.state.dataSource].rows is undefined', name: 'TypeError', stack: [ - { url: 'resource://path/data/content/bundle.js', func: 'render', line: 5529, column: 16 }, - { url: 'resource://path/data/content/vendor.bundle.js', func: 'dispatchEvent', line: 18, column: 23028 }, - { url: 'resource://path/data/content/bundle.js', func: 'wrapped', line: 7270, column: 25 }, + { filename: 'resource://path/data/content/bundle.js', function: 'render', lineno: 5529, colno: 16 }, + { + filename: 'resource://path/data/content/vendor.bundle.js', + function: 'dispatchEvent', + lineno: 18, + colno: 23028, + }, + { filename: 'resource://path/data/content/bundle.js', function: 'wrapped', lineno: 7270, colno: 25 }, ], }); }); @@ -203,11 +213,11 @@ describe('Tracekit - Firefox Tests', () => { message: 'message string', name: 'foo', stack: [ - { url: 'http://localhost:8080/file.js', func: 'baz', line: 26, column: null }, - { url: 'http://localhost:8080/file.js', func: 'foo', line: 26, column: null }, - { url: 'http://localhost:8080/file.js', func: 'eval', line: 26, column: null }, - { url: 'http://localhost:8080/file.js', func: 'speak', line: 26, column: 17 }, - { url: 'http://localhost:8080/file.js', func: '?', line: 33, column: 9 }, + { filename: 'http://localhost:8080/file.js', function: 'baz', lineno: 26, colno: undefined }, + { filename: 'http://localhost:8080/file.js', function: 'foo', lineno: 26, colno: undefined }, + { filename: 'http://localhost:8080/file.js', function: 'eval', lineno: 26, colno: undefined }, + { filename: 'http://localhost:8080/file.js', function: 'speak', lineno: 26, colno: 17 }, + { filename: 'http://localhost:8080/file.js', function: '?', lineno: 33, colno: 9 }, ], }); }); @@ -227,9 +237,9 @@ describe('Tracekit - Firefox Tests', () => { message: 'test', name: 'Error', stack: [ - { url: 'http://localhost:5000/test', func: 'fooIterator', line: 20, column: 17 }, - { url: 'http://localhost:5000/test', func: 'foo', line: 19, column: 19 }, - { url: 'http://localhost:5000/test', func: '?', line: 24, column: 7 }, + { filename: 'http://localhost:5000/test', function: 'fooIterator', lineno: 20, colno: 17 }, + { filename: 'http://localhost:5000/test', function: 'foo', lineno: 19, colno: 19 }, + { filename: 'http://localhost:5000/test', function: '?', lineno: 24, colno: 7 }, ], }); }); @@ -255,15 +265,15 @@ describe('Tracekit - Firefox Tests', () => { message: 'aha', name: 'Error', stack: [ - { url: 'http://localhost:5000/', func: 'aha', line: 19, column: 13 }, - { url: 'http://localhost:5000/', func: 'callAnotherThing', line: 20, column: 15 }, - { url: 'http://localhost:5000/', func: 'callback', line: 25, column: 7 }, - { url: 'http://localhost:5000/', func: 'test/<', line: 34, column: 7 }, - { url: 'http://localhost:5000/', func: 'test', line: 33, column: 23 }, - { url: 'http://localhost:5000/', func: 'eval', line: 39, column: null }, - { url: 'http://localhost:5000/', func: 'aha', line: 39, column: 5 }, - { url: 'http://localhost:5000/', func: 'testMethod', line: 44, column: 7 }, - { url: 'http://localhost:5000/', func: '?', line: 50, column: 19 }, + { filename: 'http://localhost:5000/', function: 'aha', lineno: 19, colno: 13 }, + { filename: 'http://localhost:5000/', function: 'callAnotherThing', lineno: 20, colno: 15 }, + { filename: 'http://localhost:5000/', function: 'callback', lineno: 25, colno: 7 }, + { filename: 'http://localhost:5000/', function: 'test/<', lineno: 34, colno: 7 }, + { filename: 'http://localhost:5000/', function: 'test', lineno: 33, colno: 23 }, + { filename: 'http://localhost:5000/', function: 'eval', lineno: 39, colno: undefined }, + { filename: 'http://localhost:5000/', function: 'aha', lineno: 39, colno: 5 }, + { filename: 'http://localhost:5000/', function: 'testMethod', lineno: 44, colno: 7 }, + { filename: 'http://localhost:5000/', function: '?', lineno: 50, colno: 19 }, ], }); }); diff --git a/packages/browser/test/unit/tracekit/ie.test.ts b/packages/browser/test/unit/tracekit/ie.test.ts index 7d016802175d..f746335d9cb3 100644 --- a/packages/browser/test/unit/tracekit/ie.test.ts +++ b/packages/browser/test/unit/tracekit/ie.test.ts @@ -21,9 +21,9 @@ describe('Tracekit - IE Tests', () => { message: "Unable to get property 'undef' of undefined or null reference", name: 'foo', stack: [ - { url: 'http://path/to/file.js', func: 'Anonymous function', line: 48, column: 13 }, - { url: 'http://path/to/file.js', func: 'foo', line: 46, column: 9 }, - { url: 'http://path/to/file.js', func: 'bar', line: 82, column: 1 }, + { filename: 'http://path/to/file.js', function: 'Anonymous function', lineno: 48, colno: 13 }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 46, colno: 9 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 82, colno: 1 }, ], }); }); @@ -48,9 +48,9 @@ describe('Tracekit - IE Tests', () => { message: "Unable to get property 'undef' of undefined or null reference", name: 'TypeError', stack: [ - { url: 'http://path/to/file.js', func: 'Anonymous function', line: 47, column: 21 }, - { url: 'http://path/to/file.js', func: 'foo', line: 45, column: 13 }, - { url: 'http://path/to/file.js', func: 'bar', line: 108, column: 1 }, + { filename: 'http://path/to/file.js', function: 'Anonymous function', lineno: 47, colno: 21 }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 45, colno: 13 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 108, colno: 1 }, ], }); }); @@ -74,9 +74,9 @@ describe('Tracekit - IE Tests', () => { message: "'getExceptionProps' is undefined", name: 'ReferenceError', stack: [ - { url: 'eval code', func: 'eval code', line: 1, column: 1 }, - { url: 'http://path/to/file.js', func: 'foo', line: 58, column: 17 }, - { url: 'http://path/to/file.js', func: 'bar', line: 109, column: 1 }, + { filename: 'eval code', function: 'eval code', lineno: 1, colno: 1 }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 58, colno: 17 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 109, colno: 1 }, ], }); }); diff --git a/packages/browser/test/unit/tracekit/misc.test.ts b/packages/browser/test/unit/tracekit/misc.test.ts index 0ec51e94c26a..936f049484a8 100644 --- a/packages/browser/test/unit/tracekit/misc.test.ts +++ b/packages/browser/test/unit/tracekit/misc.test.ts @@ -17,9 +17,9 @@ describe('Tracekit - Misc Tests', () => { message: 'bar', name: 'foo', stack: [ - { url: 'file:///path/to/file.js', func: '?', line: 878, column: null }, - { url: 'http://path/to/file.js', func: 'foo', line: 4283, column: null }, - { url: 'http://path/to/file.js', func: '?', line: 4287, column: null }, + { filename: 'file:///path/to/file.js', function: '?', lineno: 878, colNo: undefined }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 4283, colNo: undefined }, + { filename: 'http://path/to/file.js', function: '?', lineno: 4287, colNo: undefined }, ], }); }); diff --git a/packages/browser/test/unit/tracekit/opera.test.ts b/packages/browser/test/unit/tracekit/opera.test.ts index 5df2ba4a78ae..c45c703c5230 100644 --- a/packages/browser/test/unit/tracekit/opera.test.ts +++ b/packages/browser/test/unit/tracekit/opera.test.ts @@ -30,13 +30,13 @@ describe('Tracekit - Opera Tests', () => { message: 'Statement on line 42: Type mismatch (usually non-object value supplied where object required)', name: 'foo', stack: [ - { url: 'http://path/to/file.js', func: '?', line: 42, column: null }, - { url: 'http://path/to/file.js', func: '?', line: 27, column: null }, - { url: 'http://path/to/file.js', func: 'printStackTrace', line: 18, column: null }, - { url: 'http://path/to/file.js', func: 'bar', line: 4, column: null }, - { url: 'http://path/to/file.js', func: 'bar', line: 7, column: null }, - { url: 'http://path/to/file.js', func: 'foo', line: 11, column: null }, - { url: 'http://path/to/file.js', func: '?', line: 15, column: null }, + { filename: 'http://path/to/file.js', function: '?', lineno: 42, colno: undefined }, + { filename: 'http://path/to/file.js', function: '?', lineno: 27, colno: undefined }, + { filename: 'http://path/to/file.js', function: 'printStackTrace', lineno: 18, colno: undefined }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 4, colno: undefined }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 7, colno: undefined }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 11, colno: undefined }, + { filename: 'http://path/to/file.js', function: '?', lineno: 15, colno: undefined }, ], }); }); @@ -74,13 +74,13 @@ describe('Tracekit - Opera Tests', () => { message: "'this.undef' is not a function", name: 'foo', stack: [ - { url: 'http://path/to/file.js', func: 'createException', line: 42, column: 12 }, - { url: 'http://path/to/file.js', func: 'run', line: 27, column: 8 }, - { url: 'http://path/to/file.js', func: 'printStackTrace', line: 18, column: 4 }, - { url: 'http://path/to/file.js', func: 'bar', line: 4, column: 5 }, - { url: 'http://path/to/file.js', func: 'bar', line: 7, column: 4 }, - { url: 'http://path/to/file.js', func: 'foo', line: 11, column: 4 }, - { url: 'http://path/to/file.js', func: '?', line: 15, column: 3 }, + { filename: 'http://path/to/file.js', function: 'createException', lineno: 42, colno: 12 }, + { filename: 'http://path/to/file.js', function: 'run', lineno: 27, colno: 8 }, + { filename: 'http://path/to/file.js', function: 'printStackTrace', lineno: 18, colno: 4 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 4, colno: 5 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 7, colno: 4 }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 11, colno: 4 }, + { filename: 'http://path/to/file.js', function: '?', lineno: 15, colno: 3 }, ], }); }); @@ -109,9 +109,14 @@ describe('Tracekit - Opera Tests', () => { message: "Cannot convert 'x' to object", name: 'foo', stack: [ - { url: 'http://localhost:8000/ExceptionLab.html', func: '', line: 48, column: 12 }, - { url: 'http://localhost:8000/ExceptionLab.html', func: 'dumpException3', line: 46, column: 8 }, - { url: 'http://localhost:8000/ExceptionLab.html', func: '', line: 1, column: 0 }, + { + filename: 'http://localhost:8000/ExceptionLab.html', + function: '', + lineno: 48, + colno: 12, + }, + { filename: 'http://localhost:8000/ExceptionLab.html', function: 'dumpException3', lineno: 46, colno: 8 }, + { filename: 'http://localhost:8000/ExceptionLab.html', function: '', lineno: 1, colno: 0 }, ], }); }); @@ -133,9 +138,9 @@ describe('Tracekit - Opera Tests', () => { message: "Cannot read property 'undef' of null", name: 'TypeError', stack: [ - { url: 'http://path/to/file.js', func: '?', line: 47, column: 22 }, - { url: 'http://path/to/file.js', func: 'foo', line: 52, column: 15 }, - { url: 'http://path/to/file.js', func: 'bar', line: 108, column: 168 }, + { filename: 'http://path/to/file.js', function: '?', lineno: 47, colno: 22 }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 52, colno: 15 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 108, colno: 168 }, ], }); }); diff --git a/packages/browser/test/unit/tracekit/react-native.test.ts b/packages/browser/test/unit/tracekit/react-native.test.ts index eb8ed1d521ab..756ae6557e11 100644 --- a/packages/browser/test/unit/tracekit/react-native.test.ts +++ b/packages/browser/test/unit/tracekit/react-native.test.ts @@ -20,13 +20,13 @@ describe('Tracekit - React Native Tests', () => { message: 'Manually triggered crash to test Sentry reporting', name: 'Error', stack: [ - { url: 'index.android.bundle', func: 'Object.onPress', line: 2342, column: 3773 }, - { url: 'index.android.bundle', func: 's.touchableHandlePress', line: 214, column: 2048 }, - { url: 'index.android.bundle', func: 's._performSideEffectsForTransition', line: 198, column: 9608 }, - { url: 'index.android.bundle', func: 's._receiveSignal', line: 198, column: 8309 }, - { url: 'index.android.bundle', func: 's.touchableHandleResponderRelease', line: 198, column: 5615 }, - { url: 'index.android.bundle', func: 'Object.y', line: 93, column: 571 }, - { url: 'index.android.bundle', func: 'P', line: 93, column: 714 }, + { filename: 'index.android.bundle', function: 'Object.onPress', lineno: 2342, colno: 3773 }, + { filename: 'index.android.bundle', function: 's.touchableHandlePress', lineno: 214, colno: 2048 }, + { filename: 'index.android.bundle', function: 's._performSideEffectsForTransition', lineno: 198, colno: 9608 }, + { filename: 'index.android.bundle', function: 's._receiveSignal', lineno: 198, colno: 8309 }, + { filename: 'index.android.bundle', function: 's.touchableHandleResponderRelease', lineno: 198, colno: 5615 }, + { filename: 'index.android.bundle', function: 'Object.y', lineno: 93, colno: 571 }, + { filename: 'index.android.bundle', function: 'P', lineno: 93, colno: 714 }, ], }); }); @@ -48,30 +48,34 @@ describe('Tracekit - React Native Tests', () => { name: 'Error', stack: [ { - url: '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', - func: 'onPress', - line: 595, - column: 658, + filename: + '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', + function: 'onPress', + lineno: 595, + colno: 658, }, { - url: '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', - func: 'value', - line: 221, - column: 7656, + filename: + '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', + function: 'value', + lineno: 221, + colno: 7656, }, { - url: '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', - func: 'onResponderRelease', - line: 221, - column: 5666, + filename: + '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', + function: 'onResponderRelease', + lineno: 221, + colno: 5666, }, { - url: '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', - func: 'p', - line: 96, - column: 385, + filename: + '/data/user/0/com.sentrytest/files/.expo-internal/bundle-613EDD44F3305B9D75D4679663900F2BCDDDC326F247CA3202A3A4219FD412D3', + function: 'p', + lineno: 96, + colno: 385, }, - { url: '[native code]', func: 'forEach', line: null, column: null }, + { filename: '[native code]', function: 'forEach', lineno: undefined, colno: undefined }, ], }); }); @@ -99,52 +103,59 @@ describe('Tracekit - React Native Tests', () => { name: 'Error', stack: [ { - url: '/home/username/sample-workspace/sampleapp.collect.react/src/components/GpsMonitorScene.js', - func: 'render', - line: 78, - column: 24, + filename: '/home/username/sample-workspace/sampleapp.collect.react/src/components/GpsMonitorScene.js', + function: 'render', + lineno: 78, + colno: 24, }, { - url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js', - func: '_renderValidatedComponentWithoutOwnerOrContext', - line: 1050, - column: 29, + filename: + '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js', + function: '_renderValidatedComponentWithoutOwnerOrContext', + lineno: 1050, + colno: 29, }, { - url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js', - func: '_renderValidatedComponent', - line: 1075, - column: 15, + filename: + '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js', + function: '_renderValidatedComponent', + lineno: 1075, + colno: 15, }, { - url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js', - func: 'renderedElement', - line: 484, - column: 29, + filename: + '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js', + function: 'renderedElement', + lineno: 484, + colno: 29, }, { - url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js', - func: '_currentElement', - line: 346, - column: 40, + filename: + '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js', + function: '_currentElement', + lineno: 346, + colno: 40, }, { - url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactReconciler.js', - func: 'child', - line: 68, - column: 25, + filename: + '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactReconciler.js', + function: 'child', + lineno: 68, + colno: 25, }, { - url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactMultiChild.js', - func: 'children', - line: 264, - column: 10, + filename: + '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/shared/stack/reconciler/ReactMultiChild.js', + function: 'children', + lineno: 264, + colno: 10, }, { - url: '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/native/ReactNativeBaseComponent.js', - func: 'this', - line: 74, - column: 41, + filename: + '/home/username/sample-workspace/sampleapp.collect.react/node_modules/react-native/Libraries/Renderer/src/renderers/native/ReactNativeBaseComponent.js', + function: 'this', + lineno: 74, + colno: 41, }, ], }); @@ -200,43 +211,48 @@ describe('Tracekit - React Native Tests', () => { message: 'Error: test', name: 'Error', stack: [ - { url: 'index.android.bundle', func: 'value', line: 12, column: 1917 }, - { url: 'index.android.bundle', func: 'onPress', line: 12, column: 2336 }, - { url: 'index.android.bundle', func: 'touchableHandlePress', line: 258, column: 1497 }, - { url: '[native code]', func: '?', line: null, column: null }, - { url: 'index.android.bundle', func: '_performSideEffectsForTransition', line: 252, column: 8508 }, - { url: '[native code]', func: '?', line: null, column: null }, - { url: 'index.android.bundle', func: '_receiveSignal', line: 252, column: 7291 }, - { url: '[native code]', func: '?', line: null, column: null }, - { url: 'index.android.bundle', func: 'touchableHandleResponderRelease', line: 252, column: 4735 }, - { url: '[native code]', func: '?', line: null, column: null }, - { url: 'index.android.bundle', func: 'u', line: 79, column: 142 }, - { url: 'index.android.bundle', func: 'invokeGuardedCallback', line: 79, column: 459 }, - { url: 'index.android.bundle', func: 'invokeGuardedCallbackAndCatchFirstError', line: 79, column: 580 }, - { url: 'index.android.bundle', func: 'c', line: 95, column: 365 }, - { url: 'index.android.bundle', func: 'a', line: 95, column: 567 }, - { url: 'index.android.bundle', func: 'v', line: 146, column: 501 }, - { url: 'index.android.bundle', func: 'g', line: 146, column: 604 }, - { url: '[native code]', func: 'forEach', line: null, column: null }, - { url: 'index.android.bundle', func: 'i', line: 149, column: 80 }, - { url: 'index.android.bundle', func: 'processEventQueue', line: 146, column: 1432 }, - { url: 'index.android.bundle', func: 's', line: 157, column: 88 }, - { url: 'index.android.bundle', func: 'handleTopLevel', line: 157, column: 174 }, - { url: 'index.android.bundle', func: '?', line: 156, column: 572 }, - { url: 'index.android.bundle', func: 'a', line: 93, column: 276 }, - { url: 'index.android.bundle', func: 'c', line: 93, column: 60 }, - { url: 'index.android.bundle', func: 'perform', line: 177, column: 596 }, - { url: 'index.android.bundle', func: 'batchedUpdates', line: 188, column: 464 }, - { url: 'index.android.bundle', func: 'i', line: 176, column: 358 }, - { url: 'index.android.bundle', func: 'i', line: 93, column: 90 }, - { url: 'index.android.bundle', func: 'u', line: 93, column: 150 }, - { url: 'index.android.bundle', func: '_receiveRootNodeIDEvent', line: 156, column: 544 }, - { url: 'index.android.bundle', func: 'receiveTouches', line: 156, column: 918 }, - { url: 'index.android.bundle', func: 'value', line: 29, column: 3016 }, - { url: 'index.android.bundle', func: '?', line: 29, column: 955 }, - { url: 'index.android.bundle', func: 'value', line: 29, column: 2417 }, - { url: 'index.android.bundle', func: 'value', line: 29, column: 927 }, - { url: '[native code]', func: '?', line: null, column: null }, + { filename: 'index.android.bundle', function: 'value', lineno: 12, colno: 1917 }, + { filename: 'index.android.bundle', function: 'onPress', lineno: 12, colno: 2336 }, + { filename: 'index.android.bundle', function: 'touchableHandlePress', lineno: 258, colno: 1497 }, + { filename: '[native code]', function: '?', lineno: undefined, colno: undefined }, + { filename: 'index.android.bundle', function: '_performSideEffectsForTransition', lineno: 252, colno: 8508 }, + { filename: '[native code]', function: '?', lineno: undefined, colno: undefined }, + { filename: 'index.android.bundle', function: '_receiveSignal', lineno: 252, colno: 7291 }, + { filename: '[native code]', function: '?', lineno: undefined, colno: undefined }, + { filename: 'index.android.bundle', function: 'touchableHandleResponderRelease', lineno: 252, colno: 4735 }, + { filename: '[native code]', function: '?', lineno: undefined, colno: undefined }, + { filename: 'index.android.bundle', function: 'u', lineno: 79, colno: 142 }, + { filename: 'index.android.bundle', function: 'invokeGuardedCallback', lineno: 79, colno: 459 }, + { + filename: 'index.android.bundle', + function: 'invokeGuardedCallbackAndCatchFirstError', + lineno: 79, + colno: 580, + }, + { filename: 'index.android.bundle', function: 'c', lineno: 95, colno: 365 }, + { filename: 'index.android.bundle', function: 'a', lineno: 95, colno: 567 }, + { filename: 'index.android.bundle', function: 'v', lineno: 146, colno: 501 }, + { filename: 'index.android.bundle', function: 'g', lineno: 146, colno: 604 }, + { filename: '[native code]', function: 'forEach', lineno: undefined, colno: undefined }, + { filename: 'index.android.bundle', function: 'i', lineno: 149, colno: 80 }, + { filename: 'index.android.bundle', function: 'processEventQueue', lineno: 146, colno: 1432 }, + { filename: 'index.android.bundle', function: 's', lineno: 157, colno: 88 }, + { filename: 'index.android.bundle', function: 'handleTopLevel', lineno: 157, colno: 174 }, + { filename: 'index.android.bundle', function: '?', lineno: 156, colno: 572 }, + { filename: 'index.android.bundle', function: 'a', lineno: 93, colno: 276 }, + { filename: 'index.android.bundle', function: 'c', lineno: 93, colno: 60 }, + { filename: 'index.android.bundle', function: 'perform', lineno: 177, colno: 596 }, + { filename: 'index.android.bundle', function: 'batchedUpdates', lineno: 188, colno: 464 }, + { filename: 'index.android.bundle', function: 'i', lineno: 176, colno: 358 }, + { filename: 'index.android.bundle', function: 'i', lineno: 93, colno: 90 }, + { filename: 'index.android.bundle', function: 'u', lineno: 93, colno: 150 }, + { filename: 'index.android.bundle', function: '_receiveRootNodeIDEvent', lineno: 156, colno: 544 }, + { filename: 'index.android.bundle', function: 'receiveTouches', lineno: 156, colno: 918 }, + { filename: 'index.android.bundle', function: 'value', lineno: 29, colno: 3016 }, + { filename: 'index.android.bundle', function: '?', lineno: 29, colno: 955 }, + { filename: 'index.android.bundle', function: 'value', lineno: 29, colno: 2417 }, + { filename: 'index.android.bundle', function: 'value', lineno: 29, colno: 927 }, + { filename: '[native code]', function: '?', lineno: undefined, colno: undefined }, ], }); }); @@ -279,32 +295,32 @@ describe('Tracekit - React Native Tests', () => { message: 'Error: lets throw!', name: 'Error', stack: [ - { url: 'index.android.bundle', func: 'onPress', line: 1, column: 452701 }, - { url: 'index.android.bundle', func: 'anonymous', line: 1, column: 224280 }, - { url: 'index.android.bundle', func: '_performSideEffectsForTransition', line: 1, column: 230843 }, - { url: 'native', func: '_receiveSignal', line: null, column: null }, - { url: 'native', func: 'touchableHandleResponderRelease', line: null, column: null }, - { url: 'native', func: 'onResponderRelease', line: null, column: null }, - { url: 'native', func: 'apply', line: null, column: null }, - { url: 'index.android.bundle', func: 'b', line: 1, column: 74037 }, - { url: 'native', func: 'apply', line: null, column: null }, - { url: 'index.android.bundle', func: 'k', line: 1, column: 74094 }, - { url: 'native', func: 'apply', line: null, column: null }, - { url: 'index.android.bundle', func: 'C', line: 1, column: 74126 }, - { url: 'index.android.bundle', func: 'N', line: 1, column: 74267 }, - { url: 'index.android.bundle', func: 'A', line: 1, column: 74709 }, - { url: 'native', func: 'forEach', line: null, column: null }, - { url: 'index.android.bundle', func: 'z', line: 1, column: 74642 }, - { url: 'index.android.bundle', func: 'anonymous', line: 1, column: 77747 }, - { url: 'index.android.bundle', func: '_e', line: 1, column: 127755 }, - { url: 'index.android.bundle', func: 'Ne', line: 1, column: 77238 }, - { url: 'index.android.bundle', func: 'Ue', line: 1, column: 77571 }, - { url: 'index.android.bundle', func: 'receiveTouches', line: 1, column: 122512 }, - { url: 'native', func: 'apply', line: null, column: null }, - { url: 'index.android.bundle', func: 'value', line: 1, column: 33176 }, - { url: 'index.android.bundle', func: 'anonymous', line: 1, column: 31603 }, - { url: 'index.android.bundle', func: 'value', line: 1, column: 32776 }, - { url: 'index.android.bundle', func: 'value', line: 1, column: 31561 }, + { filename: 'index.android.bundle', function: 'onPress', lineno: 1, colno: 452701 }, + { filename: 'index.android.bundle', function: 'anonymous', lineno: 1, colno: 224280 }, + { filename: 'index.android.bundle', function: '_performSideEffectsForTransition', lineno: 1, colno: 230843 }, + { filename: 'native', function: '_receiveSignal', lineno: undefined, colno: undefined }, + { filename: 'native', function: 'touchableHandleResponderRelease', lineno: undefined, colno: undefined }, + { filename: 'native', function: 'onResponderRelease', lineno: undefined, colno: undefined }, + { filename: 'native', function: 'apply', lineno: undefined, colno: undefined }, + { filename: 'index.android.bundle', function: 'b', lineno: 1, colno: 74037 }, + { filename: 'native', function: 'apply', lineno: undefined, colno: undefined }, + { filename: 'index.android.bundle', function: 'k', lineno: 1, colno: 74094 }, + { filename: 'native', function: 'apply', lineno: undefined, colno: undefined }, + { filename: 'index.android.bundle', function: 'C', lineno: 1, colno: 74126 }, + { filename: 'index.android.bundle', function: 'N', lineno: 1, colno: 74267 }, + { filename: 'index.android.bundle', function: 'A', lineno: 1, colno: 74709 }, + { filename: 'native', function: 'forEach', lineno: undefined, colno: undefined }, + { filename: 'index.android.bundle', function: 'z', lineno: 1, colno: 74642 }, + { filename: 'index.android.bundle', function: 'anonymous', lineno: 1, colno: 77747 }, + { filename: 'index.android.bundle', function: '_e', lineno: 1, colno: 127755 }, + { filename: 'index.android.bundle', function: 'Ne', lineno: 1, colno: 77238 }, + { filename: 'index.android.bundle', function: 'Ue', lineno: 1, colno: 77571 }, + { filename: 'index.android.bundle', function: 'receiveTouches', lineno: 1, colno: 122512 }, + { filename: 'native', function: 'apply', lineno: undefined, colno: undefined }, + { filename: 'index.android.bundle', function: 'value', lineno: 1, colno: 33176 }, + { filename: 'index.android.bundle', function: 'anonymous', lineno: 1, colno: 31603 }, + { filename: 'index.android.bundle', function: 'value', lineno: 1, colno: 32776 }, + { filename: 'index.android.bundle', function: 'value', lineno: 1, colno: 31561 }, ], }); }); diff --git a/packages/browser/test/unit/tracekit/react.test.ts b/packages/browser/test/unit/tracekit/react.test.ts index 7f648ff39593..caa5e832d2ec 100644 --- a/packages/browser/test/unit/tracekit/react.test.ts +++ b/packages/browser/test/unit/tracekit/react.test.ts @@ -21,10 +21,10 @@ describe('Tracekit - React Tests', () => { 'Minified React error #31; visit https://reactjs.org/docs/error-decoder.html?invariant=31&args[]=object%20with%20keys%20%7B%7D&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings. ', name: 'Invariant Violation', stack: [ - { url: 'http://localhost:5000/static/js/foo.chunk.js', func: '?', line: 1, column: 21738 }, - { url: 'http://localhost:5000/static/js/foo.chunk.js', func: 'a', line: 1, column: 21841 }, - { url: 'http://localhost:5000/static/js/foo.chunk.js', func: 'ho', line: 1, column: 68735 }, - { url: 'http://localhost:5000/', func: 'f', line: 1, column: 980 }, + { filename: 'http://localhost:5000/static/js/foo.chunk.js', function: '?', lineno: 1, colno: 21738 }, + { filename: 'http://localhost:5000/static/js/foo.chunk.js', function: 'a', lineno: 1, colno: 21841 }, + { filename: 'http://localhost:5000/static/js/foo.chunk.js', function: 'ho', lineno: 1, colno: 68735 }, + { filename: 'http://localhost:5000/', function: 'f', lineno: 1, colno: 980 }, ], }); }); @@ -48,10 +48,10 @@ describe('Tracekit - React Tests', () => { '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: [ - { url: 'http://localhost:5000/static/js/foo.chunk.js', func: '?', line: 1, column: 21738 }, - { url: 'http://localhost:5000/static/js/foo.chunk.js', func: 'a', line: 1, column: 21841 }, - { url: 'http://localhost:5000/static/js/foo.chunk.js', func: 'ho', line: 1, column: 68735 }, - { url: 'http://localhost:5000/', func: 'f', line: 1, column: 980 }, + { filename: 'http://localhost:5000/static/js/foo.chunk.js', function: '?', lineno: 1, colno: 21738 }, + { filename: 'http://localhost:5000/static/js/foo.chunk.js', function: 'a', lineno: 1, colno: 21841 }, + { filename: 'http://localhost:5000/static/js/foo.chunk.js', function: 'ho', lineno: 1, colno: 68735 }, + { filename: 'http://localhost:5000/', function: 'f', lineno: 1, colno: 980 }, ], }); }); @@ -76,10 +76,10 @@ describe('Tracekit - React Tests', () => { '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: [ - { url: 'http://localhost:5000/static/js/foo.chunk.js', func: '?', line: 1, column: 21738 }, - { url: 'http://localhost:5000/static/js/foo.chunk.js', func: 'a', line: 1, column: 21841 }, - { url: 'http://localhost:5000/static/js/foo.chunk.js', func: 'ho', line: 1, column: 68735 }, - { url: 'http://localhost:5000/', func: 'f', line: 1, column: 980 }, + { filename: 'http://localhost:5000/static/js/foo.chunk.js', function: '?', lineno: 1, colno: 21738 }, + { filename: 'http://localhost:5000/static/js/foo.chunk.js', function: 'a', lineno: 1, colno: 21841 }, + { filename: 'http://localhost:5000/static/js/foo.chunk.js', function: 'ho', lineno: 1, colno: 68735 }, + { filename: 'http://localhost:5000/', function: 'f', lineno: 1, colno: 980 }, ], }); }); diff --git a/packages/browser/test/unit/tracekit/safari.test.ts b/packages/browser/test/unit/tracekit/safari.test.ts index 55e9b4c7fb9c..7fd061365e19 100644 --- a/packages/browser/test/unit/tracekit/safari.test.ts +++ b/packages/browser/test/unit/tracekit/safari.test.ts @@ -20,10 +20,10 @@ describe('Tracekit - Safari Tests', () => { message: "'null' is not an object (evaluating 'x.undef')", name: 'foo', stack: [ - { url: 'http://path/to/file.js', func: '?', line: 48, column: null }, - { url: 'http://path/to/file.js', func: 'dumpException3', line: 52, column: null }, - { url: 'http://path/to/file.js', func: 'onclick', line: 82, column: null }, - { url: '[native code]', func: '?', line: null, column: null }, + { filename: 'http://path/to/file.js', function: '?', lineno: 48, colno: undefined }, + { filename: 'http://path/to/file.js', function: 'dumpException3', lineno: 52, colno: undefined }, + { filename: 'http://path/to/file.js', function: 'onclick', lineno: 82, colno: undefined }, + { filename: '[native code]', function: '?', lineno: undefined, colno: undefined }, ], }); }); @@ -44,9 +44,9 @@ describe('Tracekit - Safari Tests', () => { message: "'null' is not an object (evaluating 'x.undef')", name: 'TypeError', stack: [ - { url: 'http://path/to/file.js', func: '?', line: 48, column: 22 }, - { url: 'http://path/to/file.js', func: 'foo', line: 52, column: 15 }, - { url: 'http://path/to/file.js', func: 'bar', line: 108, column: 107 }, + { filename: 'http://path/to/file.js', function: '?', lineno: 48, colno: 22 }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 52, colno: 15 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 108, colno: 107 }, ], }); }); @@ -68,9 +68,9 @@ describe('Tracekit - Safari Tests', () => { message: "null is not an object (evaluating 'x.undef')", name: 'TypeError', stack: [ - { url: 'http://path/to/file.js', func: '?', line: 47, column: 22 }, - { url: 'http://path/to/file.js', func: 'foo', line: 52, column: 15 }, - { url: 'http://path/to/file.js', func: 'bar', line: 108, column: 23 }, + { filename: 'http://path/to/file.js', function: '?', lineno: 47, colno: 22 }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 52, colno: 15 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 108, colno: 23 }, ], }); }); @@ -96,9 +96,9 @@ describe('Tracekit - Safari Tests', () => { message: "Can't find variable: getExceptionProps", name: 'ReferenceError', stack: [ - { url: '[native code]', func: 'eval', line: null, column: null }, - { url: 'http://path/to/file.js', func: 'foo', line: 58, column: 21 }, - { url: 'http://path/to/file.js', func: 'bar', line: 109, column: 91 }, + { filename: '[native code]', function: 'eval', lineno: undefined, colno: undefined }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 58, colno: 21 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 109, colno: 91 }, ], }); }); @@ -120,16 +120,16 @@ describe('Tracekit - Safari Tests', () => { name: 'Error', stack: [ { - url: 'safari-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js', - func: 'ClipperError', - line: 223036, - column: 10, + filename: 'safari-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js', + function: 'ClipperError', + lineno: 223036, + colno: 10, }, { - url: 'safari-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js', - func: '?', - line: 3313, - column: 26, + filename: 'safari-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js', + function: '?', + lineno: 3313, + colno: 26, }, ], }); @@ -150,18 +150,18 @@ describe('Tracekit - Safari Tests', () => { name: 'TypeError', stack: [ { - url: 'safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js', - func: 'isClaimed', - line: 2, - column: 929865, + filename: 'safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js', + function: 'isClaimed', + lineno: 2, + colno: 929865, }, { - url: 'safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js', - func: '?', - line: 2, - column: 1588410, + filename: 'safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js', + function: '?', + lineno: 2, + colno: 1588410, }, - { url: '[native code]', func: 'promiseReactionJob', line: null, column: null }, + { filename: '[native code]', function: 'promiseReactionJob', lineno: undefined, colno: undefined }, ], }); }); @@ -182,16 +182,16 @@ describe('Tracekit - Safari Tests', () => { name: 'Error', stack: [ { - url: 'safari-web-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js', - func: 'ClipperError', - line: 223036, - column: 10, + filename: 'safari-web-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js', + function: 'ClipperError', + lineno: 223036, + colno: 10, }, { - url: 'safari-web-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js', - func: '?', - line: 3313, - column: 26, + filename: 'safari-web-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js', + function: '?', + lineno: 3313, + colno: 26, }, ], }); @@ -212,18 +212,18 @@ describe('Tracekit - Safari Tests', () => { name: 'TypeError', stack: [ { - url: 'safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js', - func: 'p_', - line: 29, - column: 33314, + filename: 'safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js', + function: 'p_', + lineno: 29, + colno: 33314, }, { - url: 'safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js', - func: '?', - line: 29, - column: 56027, + filename: 'safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js', + function: '?', + lineno: 29, + colno: 56027, }, - { url: '[native code]', func: 'promiseReactionJob', line: null, column: null }, + { filename: '[native code]', function: 'promiseReactionJob', lineno: undefined, colno: undefined }, ], }); }); @@ -245,10 +245,10 @@ describe('Tracekit - Safari Tests', () => { message: 'test', name: 'Error', stack: [ - { url: 'http://localhost:5000/test', func: 'fooIterator', line: 20, column: 26 }, - { url: '[native code]', func: 'map', line: null, column: null }, - { url: 'http://localhost:5000/test', func: 'foo', line: 19, column: 22 }, - { url: 'http://localhost:5000/test', func: 'global code', line: 24, column: 10 }, + { filename: 'http://localhost:5000/test', function: 'fooIterator', lineno: 20, colno: 26 }, + { filename: '[native code]', function: 'map', lineno: undefined, colno: undefined }, + { filename: 'http://localhost:5000/test', function: 'foo', lineno: 19, colno: 22 }, + { filename: 'http://localhost:5000/test', function: 'global code', lineno: 24, colno: 10 }, ], }); }); @@ -277,17 +277,17 @@ describe('Tracekit - Safari Tests', () => { message: 'aha', name: 'Error', stack: [ - { url: 'http://localhost:5000/', func: 'aha', line: 19, column: 22 }, - { url: '[native code]', func: 'aha', line: null, column: null }, - { url: 'http://localhost:5000/', func: 'callAnotherThing', line: 20, column: 16 }, - { url: 'http://localhost:5000/', func: 'callback', line: 25, column: 23 }, - { url: 'http://localhost:5000/', func: '?', line: 34, column: 25 }, - { url: '[native code]', func: 'map', line: null, column: null }, - { url: 'http://localhost:5000/', func: 'test', line: 33, column: 26 }, - { url: '[native code]', func: 'eval', line: null, column: null }, - { url: 'http://localhost:5000/', func: 'aha', line: 39, column: 9 }, - { url: 'http://localhost:5000/', func: 'testMethod', line: 44, column: 10 }, - { url: 'http://localhost:5000/', func: '?', line: 50, column: 29 }, + { filename: 'http://localhost:5000/', function: 'aha', lineno: 19, colno: 22 }, + { filename: '[native code]', function: 'aha', lineno: undefined, colno: undefined }, + { filename: 'http://localhost:5000/', function: 'callAnotherThing', lineno: 20, colno: 16 }, + { filename: 'http://localhost:5000/', function: 'callback', lineno: 25, colno: 23 }, + { filename: 'http://localhost:5000/', function: '?', lineno: 34, colno: 25 }, + { filename: '[native code]', function: 'map', lineno: undefined, colno: undefined }, + { filename: 'http://localhost:5000/', function: 'test', lineno: 33, colno: 26 }, + { filename: '[native code]', function: 'eval', lineno: undefined, colno: undefined }, + { filename: 'http://localhost:5000/', function: 'aha', lineno: 39, colno: 9 }, + { filename: 'http://localhost:5000/', function: 'testMethod', lineno: 44, colno: 10 }, + { filename: 'http://localhost:5000/', function: '?', lineno: 50, colno: 29 }, ], }); }); From 4db0290778500efc1205bd9eaf590c5314a38546 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Tue, 8 Feb 2022 01:24:15 +0000 Subject: [PATCH 3/5] Remove undefined --- .../test/unit/tracekit/chromium.test.ts | 12 +++--- .../test/unit/tracekit/firefox.test.ts | 41 +++++++++---------- .../browser/test/unit/tracekit/misc.test.ts | 6 +-- .../browser/test/unit/tracekit/opera.test.ts | 14 +++---- .../test/unit/tracekit/react-native.test.ts | 30 +++++++------- .../browser/test/unit/tracekit/safari.test.ts | 22 +++++----- 6 files changed, 62 insertions(+), 63 deletions(-) diff --git a/packages/browser/test/unit/tracekit/chromium.test.ts b/packages/browser/test/unit/tracekit/chromium.test.ts index 5d503c33d14a..c35fbb6a2a96 100644 --- a/packages/browser/test/unit/tracekit/chromium.test.ts +++ b/packages/browser/test/unit/tracekit/chromium.test.ts @@ -8,7 +8,7 @@ describe('Tracekit - Chrome Tests', () => { expect(stackFrames).toEqual({ message: 'foo', name: 'bar', - stack: [{ filename: 'native', function: 'Array.forEach', lineno: undefined, colno: undefined }], + stack: [{ filename: 'native', function: 'Array.forEach' }], }); }); @@ -164,7 +164,7 @@ describe('Tracekit - Chrome Tests', () => { message: 'Error: test', name: 'Error', stack: [ - { filename: 'native', function: 'Error', lineno: undefined, colno: undefined }, + { filename: 'native', function: 'Error' }, { filename: 'blob:http%3A//localhost%3A8080/abfc40e9-4742-44ed-9dcd-af8f99a29379', function: 's', @@ -247,7 +247,7 @@ describe('Tracekit - Chrome Tests', () => { name: 'Error', stack: [ { filename: 'http://localhost:5000/test', function: 'fooIterator', lineno: 20, colno: 17 }, - { filename: '', function: 'Array.map', lineno: undefined, colno: undefined }, + { filename: '', function: 'Array.map' }, { filename: 'http://localhost:5000/test', function: 'foo', lineno: 19, colno: 19 }, { filename: 'http://localhost:5000/test', function: '?', lineno: 24, colno: 7 }, ], @@ -281,7 +281,7 @@ describe('Tracekit - Chrome Tests', () => { { filename: 'http://localhost:5000/', function: 'callAnotherThing', lineno: 20, colno: 16 }, { filename: 'http://localhost:5000/', function: 'Object.callback', lineno: 25, colno: 7 }, { filename: 'http://localhost:5000/', function: '?', lineno: 34, colno: 17 }, - { filename: '', function: 'Array.map', lineno: undefined, colno: undefined }, + { filename: '', function: 'Array.map' }, { filename: 'http://localhost:5000/', function: 'test', lineno: 33, colno: 23 }, { filename: 'http://localhost:5000/', function: 'eval', lineno: 37, colno: 5 }, { filename: 'http://localhost:5000/', function: 'aha', lineno: 39, colno: 5 }, @@ -309,7 +309,7 @@ describe('Tracekit - Chrome Tests', () => { name: 'Error', stack: [ { filename: 'http://localhost:5000/test', function: 'fooIterator', lineno: 20, colno: 11 }, - { filename: 'native code', function: 'Array.prototype.map', lineno: undefined, colno: undefined }, + { filename: 'native code', function: 'Array.prototype.map' }, { filename: 'http://localhost:5000/test', function: 'foo', lineno: 19, colno: 9 }, { filename: 'http://localhost:5000/test', function: 'Global code', lineno: 24, colno: 7 }, ], @@ -343,7 +343,7 @@ describe('Tracekit - Chrome Tests', () => { { filename: 'http://localhost:5000/', function: 'callAnotherThing', lineno: 18, colno: 6 }, { filename: 'http://localhost:5000/', function: 'callback', lineno: 25, colno: 7 }, { filename: 'http://localhost:5000/', function: 'Anonymous function', lineno: 34, colno: 7 }, - { filename: 'native code', function: 'Array.prototype.map', lineno: undefined, colno: undefined }, + { filename: 'native code', function: 'Array.prototype.map' }, { filename: 'http://localhost:5000/', function: 'test', lineno: 33, colno: 5 }, { filename: 'eval code', function: 'eval code', lineno: 1, colno: 1 }, { filename: 'http://localhost:5000/', function: 'aha', lineno: 39, colno: 5 }, diff --git a/packages/browser/test/unit/tracekit/firefox.test.ts b/packages/browser/test/unit/tracekit/firefox.test.ts index 8f238431e92f..21a80d9a0d4e 100644 --- a/packages/browser/test/unit/tracekit/firefox.test.ts +++ b/packages/browser/test/unit/tracekit/firefox.test.ts @@ -24,18 +24,17 @@ describe('Tracekit - Firefox Tests', () => { message: 'this.undef is not a function', name: 'TypeError', stack: [ - { filename: 'http://127.0.0.1:8000/js/stacktrace.js', function: '?', lineno: 44, colno: undefined }, - { filename: 'http://127.0.0.1:8000/js/stacktrace.js', function: '?', lineno: 31, colno: undefined }, + { filename: 'http://127.0.0.1:8000/js/stacktrace.js', function: '?', lineno: 44 }, + { filename: 'http://127.0.0.1:8000/js/stacktrace.js', function: '?', lineno: 31 }, { filename: 'http://127.0.0.1:8000/js/stacktrace.js', function: 'printStackTrace', lineno: 18, - colno: undefined, }, - { filename: 'http://127.0.0.1:8000/js/file.js', function: 'bar', lineno: 13, colno: undefined }, - { filename: 'http://127.0.0.1:8000/js/file.js', function: 'bar', lineno: 16, colno: undefined }, - { filename: 'http://127.0.0.1:8000/js/file.js', function: 'foo', lineno: 20, colno: undefined }, - { filename: 'http://127.0.0.1:8000/js/file.js', function: '?', lineno: 24, colno: undefined }, + { filename: 'http://127.0.0.1:8000/js/file.js', function: 'bar', lineno: 13 }, + { filename: 'http://127.0.0.1:8000/js/file.js', function: 'bar', lineno: 16 }, + { filename: 'http://127.0.0.1:8000/js/file.js', function: 'foo', lineno: 20 }, + { filename: 'http://127.0.0.1:8000/js/file.js', function: '?', lineno: 24 }, ], }); }); @@ -63,13 +62,13 @@ describe('Tracekit - Firefox Tests', () => { message: 'bar', name: 'foo', stack: [ - { filename: 'file:///G:/js/stacktrace.js', function: '?', lineno: 44, colno: undefined }, - { filename: 'file:///G:/js/stacktrace.js', function: '?', lineno: 31, colno: undefined }, - { filename: 'file:///G:/js/stacktrace.js', function: 'printStackTrace', lineno: 18, colno: undefined }, - { filename: 'file:///G:/js/file.js', function: 'bar', lineno: 13, colno: undefined }, - { filename: 'file:///G:/js/file.js', function: 'bar', lineno: 16, colno: undefined }, - { filename: 'file:///G:/js/file.js', function: 'foo', lineno: 20, colno: undefined }, - { filename: 'file:///G:/js/file.js', function: '?', lineno: 24, colno: undefined }, + { filename: 'file:///G:/js/stacktrace.js', function: '?', lineno: 44 }, + { filename: 'file:///G:/js/stacktrace.js', function: '?', lineno: 31 }, + { filename: 'file:///G:/js/stacktrace.js', function: 'printStackTrace', lineno: 18 }, + { filename: 'file:///G:/js/file.js', function: 'bar', lineno: 13 }, + { filename: 'file:///G:/js/file.js', function: 'bar', lineno: 16 }, + { filename: 'file:///G:/js/file.js', function: 'foo', lineno: 20 }, + { filename: 'file:///G:/js/file.js', function: '?', lineno: 24 }, ], }); }); @@ -93,9 +92,9 @@ describe('Tracekit - Firefox Tests', () => { message: 'x is null', name: 'foo', stack: [ - { filename: 'http://path/to/file.js', function: '?', lineno: 48, colno: undefined }, - { filename: 'http://path/to/file.js', function: 'dumpException3', lineno: 52, colno: undefined }, - { filename: 'http://path/to/file.js', function: 'onclick', lineno: 1, colno: undefined }, + { filename: 'http://path/to/file.js', function: '?', lineno: 48 }, + { filename: 'http://path/to/file.js', function: 'dumpException3', lineno: 52 }, + { filename: 'http://path/to/file.js', function: 'onclick', lineno: 1 }, ], }); }); @@ -213,9 +212,9 @@ describe('Tracekit - Firefox Tests', () => { message: 'message string', name: 'foo', stack: [ - { filename: 'http://localhost:8080/file.js', function: 'baz', lineno: 26, colno: undefined }, - { filename: 'http://localhost:8080/file.js', function: 'foo', lineno: 26, colno: undefined }, - { filename: 'http://localhost:8080/file.js', function: 'eval', lineno: 26, colno: undefined }, + { filename: 'http://localhost:8080/file.js', function: 'baz', lineno: 26 }, + { filename: 'http://localhost:8080/file.js', function: 'foo', lineno: 26 }, + { filename: 'http://localhost:8080/file.js', function: 'eval', lineno: 26 }, { filename: 'http://localhost:8080/file.js', function: 'speak', lineno: 26, colno: 17 }, { filename: 'http://localhost:8080/file.js', function: '?', lineno: 33, colno: 9 }, ], @@ -270,7 +269,7 @@ describe('Tracekit - Firefox Tests', () => { { filename: 'http://localhost:5000/', function: 'callback', lineno: 25, colno: 7 }, { filename: 'http://localhost:5000/', function: 'test/<', lineno: 34, colno: 7 }, { filename: 'http://localhost:5000/', function: 'test', lineno: 33, colno: 23 }, - { filename: 'http://localhost:5000/', function: 'eval', lineno: 39, colno: undefined }, + { filename: 'http://localhost:5000/', function: 'eval', lineno: 39 }, { filename: 'http://localhost:5000/', function: 'aha', lineno: 39, colno: 5 }, { filename: 'http://localhost:5000/', function: 'testMethod', lineno: 44, colno: 7 }, { filename: 'http://localhost:5000/', function: '?', lineno: 50, colno: 19 }, diff --git a/packages/browser/test/unit/tracekit/misc.test.ts b/packages/browser/test/unit/tracekit/misc.test.ts index 936f049484a8..91038d014e64 100644 --- a/packages/browser/test/unit/tracekit/misc.test.ts +++ b/packages/browser/test/unit/tracekit/misc.test.ts @@ -17,9 +17,9 @@ describe('Tracekit - Misc Tests', () => { message: 'bar', name: 'foo', stack: [ - { filename: 'file:///path/to/file.js', function: '?', lineno: 878, colNo: undefined }, - { filename: 'http://path/to/file.js', function: 'foo', lineno: 4283, colNo: undefined }, - { filename: 'http://path/to/file.js', function: '?', lineno: 4287, colNo: undefined }, + { filename: 'file:///path/to/file.js', function: '?', lineno: 878 }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 4283 }, + { filename: 'http://path/to/file.js', function: '?', lineno: 4287 }, ], }); }); diff --git a/packages/browser/test/unit/tracekit/opera.test.ts b/packages/browser/test/unit/tracekit/opera.test.ts index c45c703c5230..7d86bb68909c 100644 --- a/packages/browser/test/unit/tracekit/opera.test.ts +++ b/packages/browser/test/unit/tracekit/opera.test.ts @@ -30,13 +30,13 @@ describe('Tracekit - Opera Tests', () => { message: 'Statement on line 42: Type mismatch (usually non-object value supplied where object required)', name: 'foo', stack: [ - { filename: 'http://path/to/file.js', function: '?', lineno: 42, colno: undefined }, - { filename: 'http://path/to/file.js', function: '?', lineno: 27, colno: undefined }, - { filename: 'http://path/to/file.js', function: 'printStackTrace', lineno: 18, colno: undefined }, - { filename: 'http://path/to/file.js', function: 'bar', lineno: 4, colno: undefined }, - { filename: 'http://path/to/file.js', function: 'bar', lineno: 7, colno: undefined }, - { filename: 'http://path/to/file.js', function: 'foo', lineno: 11, colno: undefined }, - { filename: 'http://path/to/file.js', function: '?', lineno: 15, colno: undefined }, + { filename: 'http://path/to/file.js', function: '?', lineno: 42 }, + { filename: 'http://path/to/file.js', function: '?', lineno: 27 }, + { filename: 'http://path/to/file.js', function: 'printStackTrace', lineno: 18 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 4 }, + { filename: 'http://path/to/file.js', function: 'bar', lineno: 7 }, + { filename: 'http://path/to/file.js', function: 'foo', lineno: 11 }, + { filename: 'http://path/to/file.js', function: '?', lineno: 15 }, ], }); }); diff --git a/packages/browser/test/unit/tracekit/react-native.test.ts b/packages/browser/test/unit/tracekit/react-native.test.ts index 756ae6557e11..89ae3c430ca1 100644 --- a/packages/browser/test/unit/tracekit/react-native.test.ts +++ b/packages/browser/test/unit/tracekit/react-native.test.ts @@ -75,7 +75,7 @@ describe('Tracekit - React Native Tests', () => { lineno: 96, colno: 385, }, - { filename: '[native code]', function: 'forEach', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: 'forEach' }, ], }); }); @@ -214,13 +214,13 @@ describe('Tracekit - React Native Tests', () => { { filename: 'index.android.bundle', function: 'value', lineno: 12, colno: 1917 }, { filename: 'index.android.bundle', function: 'onPress', lineno: 12, colno: 2336 }, { filename: 'index.android.bundle', function: 'touchableHandlePress', lineno: 258, colno: 1497 }, - { filename: '[native code]', function: '?', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: '?' }, { filename: 'index.android.bundle', function: '_performSideEffectsForTransition', lineno: 252, colno: 8508 }, - { filename: '[native code]', function: '?', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: '?' }, { filename: 'index.android.bundle', function: '_receiveSignal', lineno: 252, colno: 7291 }, - { filename: '[native code]', function: '?', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: '?' }, { filename: 'index.android.bundle', function: 'touchableHandleResponderRelease', lineno: 252, colno: 4735 }, - { filename: '[native code]', function: '?', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: '?' }, { filename: 'index.android.bundle', function: 'u', lineno: 79, colno: 142 }, { filename: 'index.android.bundle', function: 'invokeGuardedCallback', lineno: 79, colno: 459 }, { @@ -233,7 +233,7 @@ describe('Tracekit - React Native Tests', () => { { filename: 'index.android.bundle', function: 'a', lineno: 95, colno: 567 }, { filename: 'index.android.bundle', function: 'v', lineno: 146, colno: 501 }, { filename: 'index.android.bundle', function: 'g', lineno: 146, colno: 604 }, - { filename: '[native code]', function: 'forEach', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: 'forEach' }, { filename: 'index.android.bundle', function: 'i', lineno: 149, colno: 80 }, { filename: 'index.android.bundle', function: 'processEventQueue', lineno: 146, colno: 1432 }, { filename: 'index.android.bundle', function: 's', lineno: 157, colno: 88 }, @@ -252,7 +252,7 @@ describe('Tracekit - React Native Tests', () => { { filename: 'index.android.bundle', function: '?', lineno: 29, colno: 955 }, { filename: 'index.android.bundle', function: 'value', lineno: 29, colno: 2417 }, { filename: 'index.android.bundle', function: 'value', lineno: 29, colno: 927 }, - { filename: '[native code]', function: '?', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: '?' }, ], }); }); @@ -298,25 +298,25 @@ describe('Tracekit - React Native Tests', () => { { filename: 'index.android.bundle', function: 'onPress', lineno: 1, colno: 452701 }, { filename: 'index.android.bundle', function: 'anonymous', lineno: 1, colno: 224280 }, { filename: 'index.android.bundle', function: '_performSideEffectsForTransition', lineno: 1, colno: 230843 }, - { filename: 'native', function: '_receiveSignal', lineno: undefined, colno: undefined }, - { filename: 'native', function: 'touchableHandleResponderRelease', lineno: undefined, colno: undefined }, - { filename: 'native', function: 'onResponderRelease', lineno: undefined, colno: undefined }, - { filename: 'native', function: 'apply', lineno: undefined, colno: undefined }, + { filename: 'native', function: '_receiveSignal' }, + { filename: 'native', function: 'touchableHandleResponderRelease' }, + { filename: 'native', function: 'onResponderRelease' }, + { filename: 'native', function: 'apply' }, { filename: 'index.android.bundle', function: 'b', lineno: 1, colno: 74037 }, - { filename: 'native', function: 'apply', lineno: undefined, colno: undefined }, + { filename: 'native', function: 'apply' }, { filename: 'index.android.bundle', function: 'k', lineno: 1, colno: 74094 }, - { filename: 'native', function: 'apply', lineno: undefined, colno: undefined }, + { filename: 'native', function: 'apply' }, { filename: 'index.android.bundle', function: 'C', lineno: 1, colno: 74126 }, { filename: 'index.android.bundle', function: 'N', lineno: 1, colno: 74267 }, { filename: 'index.android.bundle', function: 'A', lineno: 1, colno: 74709 }, - { filename: 'native', function: 'forEach', lineno: undefined, colno: undefined }, + { filename: 'native', function: 'forEach' }, { filename: 'index.android.bundle', function: 'z', lineno: 1, colno: 74642 }, { filename: 'index.android.bundle', function: 'anonymous', lineno: 1, colno: 77747 }, { filename: 'index.android.bundle', function: '_e', lineno: 1, colno: 127755 }, { filename: 'index.android.bundle', function: 'Ne', lineno: 1, colno: 77238 }, { filename: 'index.android.bundle', function: 'Ue', lineno: 1, colno: 77571 }, { filename: 'index.android.bundle', function: 'receiveTouches', lineno: 1, colno: 122512 }, - { filename: 'native', function: 'apply', lineno: undefined, colno: undefined }, + { filename: 'native', function: 'apply' }, { filename: 'index.android.bundle', function: 'value', lineno: 1, colno: 33176 }, { filename: 'index.android.bundle', function: 'anonymous', lineno: 1, colno: 31603 }, { filename: 'index.android.bundle', function: 'value', lineno: 1, colno: 32776 }, diff --git a/packages/browser/test/unit/tracekit/safari.test.ts b/packages/browser/test/unit/tracekit/safari.test.ts index 7fd061365e19..5f43e042a279 100644 --- a/packages/browser/test/unit/tracekit/safari.test.ts +++ b/packages/browser/test/unit/tracekit/safari.test.ts @@ -20,10 +20,10 @@ describe('Tracekit - Safari Tests', () => { message: "'null' is not an object (evaluating 'x.undef')", name: 'foo', stack: [ - { filename: 'http://path/to/file.js', function: '?', lineno: 48, colno: undefined }, - { filename: 'http://path/to/file.js', function: 'dumpException3', lineno: 52, colno: undefined }, - { filename: 'http://path/to/file.js', function: 'onclick', lineno: 82, colno: undefined }, - { filename: '[native code]', function: '?', lineno: undefined, colno: undefined }, + { filename: 'http://path/to/file.js', function: '?', lineno: 48 }, + { filename: 'http://path/to/file.js', function: 'dumpException3', lineno: 52 }, + { filename: 'http://path/to/file.js', function: 'onclick', lineno: 82 }, + { filename: '[native code]', function: '?' }, ], }); }); @@ -96,7 +96,7 @@ describe('Tracekit - Safari Tests', () => { message: "Can't find variable: getExceptionProps", name: 'ReferenceError', stack: [ - { filename: '[native code]', function: 'eval', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: 'eval' }, { filename: 'http://path/to/file.js', function: 'foo', lineno: 58, colno: 21 }, { filename: 'http://path/to/file.js', function: 'bar', lineno: 109, colno: 91 }, ], @@ -161,7 +161,7 @@ describe('Tracekit - Safari Tests', () => { lineno: 2, colno: 1588410, }, - { filename: '[native code]', function: 'promiseReactionJob', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: 'promiseReactionJob' }, ], }); }); @@ -223,7 +223,7 @@ describe('Tracekit - Safari Tests', () => { lineno: 29, colno: 56027, }, - { filename: '[native code]', function: 'promiseReactionJob', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: 'promiseReactionJob' }, ], }); }); @@ -246,7 +246,7 @@ describe('Tracekit - Safari Tests', () => { name: 'Error', stack: [ { filename: 'http://localhost:5000/test', function: 'fooIterator', lineno: 20, colno: 26 }, - { filename: '[native code]', function: 'map', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: 'map' }, { filename: 'http://localhost:5000/test', function: 'foo', lineno: 19, colno: 22 }, { filename: 'http://localhost:5000/test', function: 'global code', lineno: 24, colno: 10 }, ], @@ -278,13 +278,13 @@ describe('Tracekit - Safari Tests', () => { name: 'Error', stack: [ { filename: 'http://localhost:5000/', function: 'aha', lineno: 19, colno: 22 }, - { filename: '[native code]', function: 'aha', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: 'aha' }, { filename: 'http://localhost:5000/', function: 'callAnotherThing', lineno: 20, colno: 16 }, { filename: 'http://localhost:5000/', function: 'callback', lineno: 25, colno: 23 }, { filename: 'http://localhost:5000/', function: '?', lineno: 34, colno: 25 }, - { filename: '[native code]', function: 'map', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: 'map' }, { filename: 'http://localhost:5000/', function: 'test', lineno: 33, colno: 26 }, - { filename: '[native code]', function: 'eval', lineno: undefined, colno: undefined }, + { filename: '[native code]', function: 'eval' }, { filename: 'http://localhost:5000/', function: 'aha', lineno: 39, colno: 9 }, { filename: 'http://localhost:5000/', function: 'testMethod', lineno: 44, colno: 10 }, { filename: 'http://localhost:5000/', function: '?', lineno: 50, colno: 29 }, From 87c5628e329c9758b25695411a445b0453acc3c2 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Thu, 10 Feb 2022 18:18:33 +0000 Subject: [PATCH 4/5] Merge opera parser to slim down code --- packages/browser/src/tracekit.ts | 132 ++++++++----------------------- 1 file changed, 34 insertions(+), 98 deletions(-) diff --git a/packages/browser/src/tracekit.ts b/packages/browser/src/tracekit.ts index 0c59b8605821..86dcdac850f3 100644 --- a/packages/browser/src/tracekit.ts +++ b/packages/browser/src/tracekit.ts @@ -37,10 +37,13 @@ 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; +const opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i; +const opera11Regex = + / line (\d+), column (\d+)\s*(?:in (?:]+)>|([^)]+))\(.*\))? in (.*):\s*$/i; /** JSDoc */ -export function computeStackTrace(ex: Error & { framesToPop?: number }): StackTrace { - let stack; +export function computeStackTrace(ex: Error & { framesToPop?: number; stacktrace?: string }): StackTrace { + let frames: StackFrame[] = []; let popSize = 0; if (ex) { @@ -52,49 +55,52 @@ export function computeStackTrace(ex: Error & { framesToPop?: number }): StackTr } try { - // This must be tried first because Opera 10 *destroys* - // its stacktrace property if you try to access the stack - // property first!! - stack = computeStackTraceFromStacktraceProp(ex); - if (stack) { - return popFrames(stack, popSize); - } + // Access and store the stacktrace property before doing ANYTHING + // else to it because Opera is not very good at providing it + // reliably in other circumstances. + const stacktrace = ex.stacktrace || ex.stack || ''; + + frames = parseFrames(stacktrace); } catch (e) { // no-empty } - try { - stack = computeStackTraceFromStackProp(ex); - if (stack) { - return popFrames(stack, popSize); - } - } catch (e) { - // no-empty + if (frames.length && popSize > 0) { + frames = frames.slice(popSize); } return { message: extractMessage(ex), name: ex && ex.name, - stack: [], + stack: frames, }; } /** JSDoc */ // eslint-disable-next-line complexity -function computeStackTraceFromStackProp(ex: Error): StackTrace | null { - if (!ex || !ex.stack) { - return null; - } - - const stack = []; - const lines = ex.stack.split('\n'); +function parseFrames(stackString: string): StackFrame[] { + const frames: StackFrame[] = []; + const lines = stackString.split('\n'); let isEval; let submatch; let parts; - let element: StackFrame | undefined = undefined; + let element: StackFrame | undefined; for (const line of lines) { - if ((parts = chrome.exec(line))) { + if ((parts = opera10Regex.exec(line))) { + element = { + filename: parts[2], + function: parts[3] || UNKNOWN_FUNCTION, + lineno: +parts[1], + }; + } else if ((parts = opera11Regex.exec(line))) { + element = { + filename: parts[5], + function: parts[3] || parts[4] || UNKNOWN_FUNCTION, + lineno: +parts[1], + colno: +parts[2], + }; + } else if ((parts = chrome.exec(line))) { isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line if (isEval && (submatch = chromeEval.exec(parts[2]))) { // throw out eval line/column and use top-most line/column number @@ -144,68 +150,10 @@ function computeStackTraceFromStackProp(ex: Error): StackTrace | null { continue; } - stack.push(element); - } - - if (!stack.length) { - return null; - } - - return { - message: extractMessage(ex), - name: ex.name, - stack, - }; -} - -/** JSDoc */ -function computeStackTraceFromStacktraceProp(ex: Error & { stacktrace?: string }): StackTrace | null { - if (!ex || !ex.stacktrace) { - return null; - } - // Access and store the stacktrace property before doing ANYTHING - // else to it because Opera is not very good at providing it - // reliably in other circumstances. - const stacktrace = ex.stacktrace; - const opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i; - const opera11Regex = - / line (\d+), column (\d+)\s*(?:in (?:]+)>|([^)]+))\(.*\))? in (.*):\s*$/i; - const lines = stacktrace.split('\n'); - const stack = []; - let parts; - - for (const line of lines) { - let element: StackFrame | undefined = undefined; - - if ((parts = opera10Regex.exec(line))) { - element = { - filename: parts[2], - function: parts[3] || UNKNOWN_FUNCTION, - lineno: +parts[1], - }; - } else if ((parts = opera11Regex.exec(line))) { - element = { - filename: parts[5], - function: parts[3] || parts[4] || UNKNOWN_FUNCTION, - lineno: +parts[1], - colno: +parts[2], - }; - } - - if (element) { - stack.push(element); - } - } - - if (!stack.length) { - return null; + frames.push(element); } - return { - message: extractMessage(ex), - name: ex.name, - stack, - }; + return frames; } /** @@ -240,18 +188,6 @@ const extractSafariExtensionDetails = (func: string, filename: string): [string, : [func, filename]; }; -/** Remove N number of frames from the stack */ -function popFrames(stacktrace: StackTrace, popSize: number): StackTrace { - try { - return { - ...stacktrace, - stack: stacktrace.stack.slice(popSize), - }; - } catch (e) { - return stacktrace; - } -} - /** * There are cases where stacktrace.message is an Event object * https://github.com/getsentry/sentry-javascript/issues/1949 From 245eee9caa4be48eff86100b60e363699deebb24 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Thu, 10 Feb 2022 18:27:43 +0000 Subject: [PATCH 5/5] Lil tidy --- packages/browser/src/parsers.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/browser/src/parsers.ts b/packages/browser/src/parsers.ts index db9f8b532317..e7dc375ac014 100644 --- a/packages/browser/src/parsers.ts +++ b/packages/browser/src/parsers.ts @@ -81,7 +81,7 @@ export function eventFromStacktrace(stacktrace: TraceKitStackTrace): Event { * @hidden */ export function prepareFramesForEvent(stack: StackFrame[]): StackFrame[] { - if (!stack || !stack.length) { + if (!stack.length) { return []; } @@ -104,11 +104,11 @@ export function prepareFramesForEvent(stack: StackFrame[]): StackFrame[] { return localStack .slice(0, STACKTRACE_LIMIT) .map(frame => ({ - colno: frame.colno, filename: frame.filename || localStack[0].filename, function: frame.function || '?', - in_app: true, lineno: frame.lineno, + colno: frame.colno, + in_app: true, })) .reverse(); }