Skip to content

Commit 8053a19

Browse files
committed
fix(browser): Parse frames-only safari(-web)-extension stack
1 parent 314356e commit 8053a19

File tree

2 files changed

+140
-54
lines changed

2 files changed

+140
-54
lines changed

packages/browser/src/tracekit.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,8 @@ function computeStackTraceFromStackProp(ex: any): StackTrace | null {
128128
// Kamil: One more hack won't hurt us right? Understanding and adding more rules on top of these regexps right now
129129
// would be way too time consuming. (TODO: Rewrite whole RegExp to be more readable)
130130
let func = parts[1] || UNKNOWN_FUNCTION;
131-
const isSafariExtension = func.indexOf('safari-extension') !== -1;
132-
const isSafariWebExtension = func.indexOf('safari-web-extension') !== -1;
133-
if (isSafariExtension || isSafariWebExtension) {
134-
func = func.indexOf('@') !== -1 ? func.split('@')[0] : UNKNOWN_FUNCTION;
135-
url = isSafariExtension ? `safari-extension:${url}` : `safari-web-extension:${url}`;
131+
if (isSafariExtension(func) || isSafariWebExtension(func)) {
132+
[func, url] = extractSafariExtensionDetails(func, url);
136133
}
137134

138135
element = {
@@ -165,9 +162,17 @@ function computeStackTraceFromStackProp(ex: any): StackTrace | null {
165162
// NOTE: this hack doesn't work if top-most frame is eval
166163
stack[0].column = (ex.columnNumber as number) + 1;
167164
}
165+
166+
let url = parts[3];
167+
let func = parts[1] || UNKNOWN_FUNCTION;
168+
169+
if (isSafariExtension(func) || isSafariWebExtension(func)) {
170+
[func, url] = extractSafariExtensionDetails(func, url);
171+
}
172+
168173
element = {
169-
url: parts[3],
170-
func: parts[1] || UNKNOWN_FUNCTION,
174+
url,
175+
func,
171176
args: parts[2] ? parts[2].split(',') : [],
172177
line: parts[4] ? +parts[4] : null,
173178
column: parts[5] ? +parts[5] : null,
@@ -249,6 +254,15 @@ function computeStackTraceFromStacktraceProp(ex: any): StackTrace | null {
249254
};
250255
}
251256

257+
const isSafariExtension = (func: string): boolean => func.indexOf('safari-extension') !== -1;
258+
const isSafariWebExtension = (func: string): boolean => func.indexOf('safari-web-extension') !== -1;
259+
const extractSafariExtensionDetails = (func: string, url: string): [string, string] => {
260+
return [
261+
func.indexOf('@') !== -1 ? func.split('@')[0] : UNKNOWN_FUNCTION,
262+
isSafariExtension(func) ? `safari-extension:${url}` : `safari-web-extension:${url}`,
263+
];
264+
};
265+
252266
/** Remove N number of frames from the stack */
253267
function popFrames(stacktrace: StackTrace, popSize: number): StackTrace {
254268
try {

packages/browser/test/unit/tracekit/custom.test.ts

Lines changed: 119 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -24,58 +24,130 @@ describe('Tracekit - Custom Tests', () => {
2424
]);
2525
});
2626

27-
it('should parse exceptions for safari-extension', () => {
28-
const SAFARI_EXTENSION_EXCEPTION = {
29-
message: 'wat',
30-
name: 'Error',
31-
stack: `Error: wat
27+
describe('Safari extensions', () => {
28+
it('should parse exceptions for safari-extension', () => {
29+
const SAFARI_EXTENSION_EXCEPTION = {
30+
message: 'wat',
31+
name: 'Error',
32+
stack: `Error: wat
3233
at ClipperError@safari-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js:223036:10)
3334
at safari-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js:3313:26)`,
34-
};
35-
const stacktrace = computeStackTrace(SAFARI_EXTENSION_EXCEPTION);
36-
expect(stacktrace.stack).deep.equal([
37-
{
38-
url: 'safari-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js',
39-
func: 'ClipperError',
40-
args: [],
41-
line: 223036,
42-
column: 10,
43-
},
44-
{
45-
url: 'safari-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js',
46-
func: '?',
47-
args: [],
48-
line: 3313,
49-
column: 26,
50-
},
51-
]);
52-
});
35+
};
36+
const stacktrace = computeStackTrace(SAFARI_EXTENSION_EXCEPTION);
37+
expect(stacktrace.stack).deep.equal([
38+
{
39+
url: 'safari-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js',
40+
func: 'ClipperError',
41+
args: [],
42+
line: 223036,
43+
column: 10,
44+
},
45+
{
46+
url: 'safari-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js',
47+
func: '?',
48+
args: [],
49+
line: 3313,
50+
column: 26,
51+
},
52+
]);
53+
});
5354

54-
it('should parse exceptions for safari-web-extension', () => {
55-
const SAFARI_WEB_EXTENSION_EXCEPTION = {
56-
message: 'wat',
57-
name: 'Error',
58-
stack: `Error: wat
55+
it('should parse exceptions for safari-extension with frames-only stack', () => {
56+
const SAFARI_EXTENSION_EXCEPTION = {
57+
message: `undefined is not an object (evaluating 'e.groups.includes')`,
58+
name: `TypeError`,
59+
stack: `isClaimed@safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js:2:929865
60+
safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js:2:1588410
61+
promiseReactionJob@[native code]`,
62+
};
63+
const stacktrace = computeStackTrace(SAFARI_EXTENSION_EXCEPTION);
64+
65+
expect(stacktrace.stack).deep.equal([
66+
{
67+
url: 'safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js',
68+
func: 'isClaimed',
69+
args: [],
70+
line: 2,
71+
column: 929865,
72+
},
73+
{
74+
url: 'safari-extension://com.grammarly.safari.extension.ext2-W8F64X92K3/ee7759dd/Grammarly.js',
75+
func: '?',
76+
args: [],
77+
line: 2,
78+
column: 1588410,
79+
},
80+
{
81+
url: '[native code]',
82+
func: 'promiseReactionJob',
83+
args: [],
84+
line: null,
85+
column: null,
86+
},
87+
]);
88+
});
89+
90+
it('should parse exceptions for safari-web-extension', () => {
91+
const SAFARI_WEB_EXTENSION_EXCEPTION = {
92+
message: 'wat',
93+
name: 'Error',
94+
stack: `Error: wat
5995
at ClipperError@safari-web-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js:223036:10)
6096
at safari-web-extension:(//3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js:3313:26)`,
61-
};
62-
const stacktrace = computeStackTrace(SAFARI_WEB_EXTENSION_EXCEPTION);
63-
expect(stacktrace.stack).deep.equal([
64-
{
65-
url: 'safari-web-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js',
66-
func: 'ClipperError',
67-
args: [],
68-
line: 223036,
69-
column: 10,
70-
},
71-
{
72-
url: 'safari-web-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js',
73-
func: '?',
74-
args: [],
75-
line: 3313,
76-
column: 26,
77-
},
78-
]);
97+
};
98+
const stacktrace = computeStackTrace(SAFARI_WEB_EXTENSION_EXCEPTION);
99+
expect(stacktrace.stack).deep.equal([
100+
{
101+
url: 'safari-web-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/commons.js',
102+
func: 'ClipperError',
103+
args: [],
104+
line: 223036,
105+
column: 10,
106+
},
107+
{
108+
url: 'safari-web-extension://3284871F-A480-4FFC-8BC4-3F362C752446/2665fee0/topee-content.js',
109+
func: '?',
110+
args: [],
111+
line: 3313,
112+
column: 26,
113+
},
114+
]);
115+
});
116+
117+
it('should parse exceptions for safari-web-extension with frames-only stack', () => {
118+
const SAFARI_EXTENSION_EXCEPTION = {
119+
message: `undefined is not an object (evaluating 'e.groups.includes')`,
120+
name: `TypeError`,
121+
stack: `p_@safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js:29:33314
122+
safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js:29:56027
123+
promiseReactionJob@[native code]`,
124+
};
125+
const stacktrace = computeStackTrace(SAFARI_EXTENSION_EXCEPTION);
126+
127+
expect(stacktrace.stack).deep.equal([
128+
{
129+
url: 'safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js',
130+
func: 'p_',
131+
args: [],
132+
line: 29,
133+
column: 33314,
134+
},
135+
{
136+
url: 'safari-web-extension://46434E60-F5BD-48A4-80C8-A422C5D16897/scripts/content-script.js',
137+
func: '?',
138+
args: [],
139+
line: 29,
140+
column: 56027,
141+
},
142+
{
143+
url: '[native code]',
144+
func: 'promiseReactionJob',
145+
args: [],
146+
line: null,
147+
column: null,
148+
},
149+
]);
150+
});
79151
});
80152

81153
it('should parse exceptions for react-native-v8', () => {

0 commit comments

Comments
 (0)