Skip to content

Commit f6b6b3d

Browse files
committed
Add onunhandledrejection tests.
1 parent 2b89536 commit f6b6b3d

File tree

3 files changed

+243
-1
lines changed

3 files changed

+243
-1
lines changed

packages/browser/test/e2e/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist

packages/browser/test/e2e/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"dependencies": {
2323
"@babel/core": "^7.15.5",
2424
"@babel/preset-env": "^7.15.4",
25-
"@playwright/test": "^1.14.1",
25+
"@playwright/test": "1.17.0-next-alpha-nov-5-2021",
2626
"@sentry/browser": "file:../..",
2727
"babel-loader": "^8.2.2",
2828
"express": "^4.17.1",
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
const { test, expect } = require('@playwright/test');
2+
3+
const { getSentryEvents } = require('./utils/helpers');
4+
5+
test.describe('window.onunhandledrejection', () => {
6+
test.beforeEach(async ({ baseURL, page }) => {
7+
await page.goto(baseURL);
8+
});
9+
10+
test('should capture unhandledrejection with error', async ({ page, browserName }) => {
11+
const supportsOnunhandledrejection = await page.evaluate(() => typeof PromiseRejectionEvent !== 'undefined');
12+
13+
if (supportsOnunhandledrejection) {
14+
const eventData = await getSentryEvents(page, () => {
15+
Promise.reject(new Error('test'));
16+
});
17+
18+
expect(eventData[0].exception.values[0].value).toBe('test');
19+
expect(eventData[0].exception.values[0].type).toBe('Error');
20+
21+
if (browserName !== 'webkit') {
22+
expect(eventData[0].exception.values[0].stacktrace.frames.length).toBeGreaterThan(1);
23+
}
24+
25+
expect(eventData[0].exception.values[0].mechanism.handled).toBe(false);
26+
expect(eventData[0].exception.values[0].mechanism.type).toBe('onunhandledrejection');
27+
} else {
28+
return true;
29+
}
30+
});
31+
32+
// something, somewhere, (likely a browser extension) effectively casts PromiseRejectionEvents
33+
// to CustomEvents, moving the `promise` and `reason` attributes of the PRE into
34+
// the CustomEvent's `detail` attribute, since they're not part of CustomEvent's spec
35+
// see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent and
36+
// https://github.com/getsentry/sentry-javascript/issues/2380
37+
test('should capture PromiseRejectionEvent cast to CustomEvent with type unhandledrejection', async ({
38+
page,
39+
browserName,
40+
}) => {
41+
const supportsOnunhandledrejection = await page.evaluate(() => typeof PromiseRejectionEvent !== 'undefined');
42+
43+
if (supportsOnunhandledrejection) {
44+
const eventData = await getSentryEvents(page, () => {
45+
window.dispatchEvent(
46+
new CustomEvent('unhandledrejection', {
47+
detail: {
48+
promise: new Promise(function() {}),
49+
reason: new Error('test-2'),
50+
},
51+
}),
52+
);
53+
});
54+
55+
expect(eventData[0].exception.values[0].value).toBe('test-2');
56+
expect(eventData[0].exception.values[0].type).toBe('Error');
57+
58+
if (browserName !== 'webkit') {
59+
expect(eventData[0].exception.values[0].stacktrace.frames.length).toBeGreaterThan(1);
60+
}
61+
62+
expect(eventData[0].exception.values[0].mechanism.handled).toBe(false);
63+
expect(eventData[0].exception.values[0].mechanism.type).toBe('onunhandledrejection');
64+
} else {
65+
return true;
66+
}
67+
});
68+
69+
// there's no evidence that this actually happens, but it could, and our code correctly
70+
// handles it, so might as well prevent future regression on that score
71+
test('should capture a random Event with type unhandledrejection', async ({ page }) => {
72+
const supportsOnunhandledrejection = await page.evaluate(() => typeof PromiseRejectionEvent !== 'undefined');
73+
74+
if (supportsOnunhandledrejection) {
75+
const eventData = await getSentryEvents(page, () => {
76+
window.dispatchEvent(new Event('unhandledrejection'));
77+
});
78+
79+
expect(eventData[0].exception.values[0].value).toBe(
80+
'Non-Error promise rejection captured with keys: currentTarget, isTrusted, target, type',
81+
);
82+
expect(eventData[0].exception.values[0].type).toBe('Event');
83+
expect(eventData[0].exception.values[0].mechanism.handled).toBe(false);
84+
expect(eventData[0].exception.values[0].mechanism.type).toBe('onunhandledrejection');
85+
} else {
86+
return true;
87+
}
88+
});
89+
90+
test('should capture unhandledrejection with a string', async ({ page }) => {
91+
const supportsOnunhandledrejection = await page.evaluate(() => typeof PromiseRejectionEvent !== 'undefined');
92+
93+
if (supportsOnunhandledrejection) {
94+
const eventData = await getSentryEvents(page, () => {
95+
Promise.reject('test');
96+
});
97+
98+
expect(eventData[0].exception.values[0].value).toBe('Non-Error promise rejection captured with value: test');
99+
expect(eventData[0].exception.values[0].type).toBe('UnhandledRejection');
100+
expect(eventData[0].exception.values[0].mechanism.handled).toBe(false);
101+
expect(eventData[0].exception.values[0].mechanism.type).toBe('onunhandledrejection');
102+
} else {
103+
return true;
104+
}
105+
});
106+
107+
test('should capture unhandledrejection with a monster string', async ({ page }) => {
108+
const supportsOnunhandledrejection = await page.evaluate(() => typeof PromiseRejectionEvent !== 'undefined');
109+
110+
if (supportsOnunhandledrejection) {
111+
const eventData = await getSentryEvents(page, () => {
112+
Promise.reject('test'.repeat(100));
113+
});
114+
115+
expect(eventData[0].exception.values[0].value).toHaveLength(253);
116+
expect(eventData[0].exception.values[0].value).toContain('Non-Error promise rejection captured with value: ');
117+
expect(eventData[0].exception.values[0].type).toBe('UnhandledRejection');
118+
expect(eventData[0].exception.values[0].mechanism.handled).toBe(false);
119+
expect(eventData[0].exception.values[0].mechanism.type).toBe('onunhandledrejection');
120+
} else {
121+
return true;
122+
}
123+
});
124+
125+
test('should capture unhandledrejection with an object', async ({ page }) => {
126+
const supportsOnunhandledrejection = await page.evaluate(() => typeof PromiseRejectionEvent !== 'undefined');
127+
128+
if (supportsOnunhandledrejection) {
129+
const eventData = await getSentryEvents(page, () => {
130+
Promise.reject({ a: 'b', b: 'c', c: 'd' });
131+
});
132+
133+
expect(eventData[0].exception.values[0].value).toBe('Non-Error promise rejection captured with keys: a, b, c');
134+
expect(eventData[0].exception.values[0].type).toBe('UnhandledRejection');
135+
expect(eventData[0].exception.values[0].mechanism.handled).toBe(false);
136+
expect(eventData[0].exception.values[0].mechanism.type).toBe('onunhandledrejection');
137+
} else {
138+
return true;
139+
}
140+
});
141+
142+
test('should capture unhandledrejection with a monster object', async ({ page }) => {
143+
const supportsOnunhandledrejection = await page.evaluate(() => typeof PromiseRejectionEvent !== 'undefined');
144+
145+
if (supportsOnunhandledrejection) {
146+
const eventData = await getSentryEvents(page, () => {
147+
var a = {
148+
a: '1'.repeat('100'),
149+
b: '2'.repeat('100'),
150+
c: '3'.repeat('100'),
151+
};
152+
a.d = a.a;
153+
a.e = a;
154+
155+
Promise.reject(a);
156+
});
157+
158+
expect(eventData[0].exception.values[0].value).toBe(
159+
'Non-Error promise rejection captured with keys: a, b, c, d, e',
160+
);
161+
expect(eventData[0].exception.values[0].type).toBe('UnhandledRejection');
162+
expect(eventData[0].exception.values[0].mechanism.handled).toBe(false);
163+
expect(eventData[0].exception.values[0].mechanism.type).toBe('onunhandledrejection');
164+
} else {
165+
return true;
166+
}
167+
});
168+
169+
test('should capture unhandledrejection with a number', async ({ page }) => {
170+
const supportsOnunhandledrejection = await page.evaluate(() => typeof PromiseRejectionEvent !== 'undefined');
171+
172+
if (supportsOnunhandledrejection) {
173+
const eventData = await getSentryEvents(page, () => {
174+
Promise.reject(1337);
175+
});
176+
177+
expect(eventData[0].exception.values[0].value).toBe('Non-Error promise rejection captured with value: 1337');
178+
expect(eventData[0].exception.values[0].type).toBe('UnhandledRejection');
179+
expect(eventData[0].exception.values[0].mechanism.handled).toBe(false);
180+
expect(eventData[0].exception.values[0].mechanism.type).toBe('onunhandledrejection');
181+
} else {
182+
return true;
183+
}
184+
});
185+
186+
test('should capture unhandledrejection with null', async ({ page }) => {
187+
const supportsOnunhandledrejection = await page.evaluate(() => typeof PromiseRejectionEvent !== 'undefined');
188+
189+
if (supportsOnunhandledrejection) {
190+
const eventData = await getSentryEvents(page, () => {
191+
Promise.reject(null);
192+
});
193+
194+
expect(eventData[0].exception.values[0].value).toBe('Non-Error promise rejection captured with value: null');
195+
expect(eventData[0].exception.values[0].type).toBe('UnhandledRejection');
196+
expect(eventData[0].exception.values[0].mechanism.handled).toBe(false);
197+
expect(eventData[0].exception.values[0].mechanism.type).toBe('onunhandledrejection');
198+
} else {
199+
return true;
200+
}
201+
});
202+
203+
test('should capture unhandledrejection with an undefined', async ({ page }) => {
204+
const supportsOnunhandledrejection = await page.evaluate(() => typeof PromiseRejectionEvent !== 'undefined');
205+
206+
if (supportsOnunhandledrejection) {
207+
const eventData = await getSentryEvents(page, () => {
208+
Promise.reject(undefined);
209+
});
210+
211+
expect(eventData[0].exception.values[0].value).toBe('Non-Error promise rejection captured with value: undefined');
212+
expect(eventData[0].exception.values[0].type).toBe('UnhandledRejection');
213+
expect(eventData[0].exception.values[0].mechanism.handled).toBe(false);
214+
expect(eventData[0].exception.values[0].mechanism.type).toBe('onunhandledrejection');
215+
} else {
216+
return true;
217+
}
218+
});
219+
220+
test('should skip our own failed requests that somehow bubbled-up to unhandledrejection handler', async ({
221+
page,
222+
}) => {
223+
const supportsOnunhandledrejection = await page.evaluate(() => typeof PromiseRejectionEvent !== 'undefined');
224+
225+
if (supportsOnunhandledrejection) {
226+
const eventData = await getSentryEvents(page, () => {
227+
Promise.reject({
228+
__sentry_own_request__: true,
229+
});
230+
Promise.reject({
231+
__sentry_own_request__: false,
232+
});
233+
Promise.reject({});
234+
});
235+
236+
expect(eventData).toHaveLength(2);
237+
} else {
238+
return true;
239+
}
240+
});
241+
});

0 commit comments

Comments
 (0)