Skip to content

Commit 69461f1

Browse files
committed
feat: Send bodies as JSON
1 parent 27eda57 commit 69461f1

File tree

12 files changed

+680
-111
lines changed

12 files changed

+680
-111
lines changed

packages/browser-integration-tests/suites/replay/extendNetworkBreadcrumbs/fetch/captureBodies/test.ts

Lines changed: 76 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -8,91 +8,94 @@ import {
88
waitForReplayRequest,
99
} from '../../../../../utils/replayHelpers';
1010

11-
sentryTest('captures requestBody & responseBody when experiment is configured', async ({ getLocalTestPath, page }) => {
12-
if (shouldSkipReplayTest()) {
13-
sentryTest.skip();
14-
}
11+
sentryTest(
12+
'captures text requestBody & responseBody when experiment is configured',
13+
async ({ getLocalTestPath, page }) => {
14+
if (shouldSkipReplayTest()) {
15+
sentryTest.skip();
16+
}
1517

16-
await page.route('**/foo', route => {
17-
return route.fulfill({
18-
status: 200,
19-
body: JSON.stringify({ res: 'this' }),
20-
headers: {
21-
'Content-Type': 'application/json',
22-
},
18+
await page.route('**/foo', route => {
19+
return route.fulfill({
20+
status: 200,
21+
body: 'response body',
22+
headers: {
23+
'Content-Type': 'application/json',
24+
},
25+
});
2326
});
24-
});
2527

26-
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
27-
return route.fulfill({
28-
status: 200,
29-
contentType: 'application/json',
30-
body: JSON.stringify({ id: 'test-id' }),
28+
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
29+
return route.fulfill({
30+
status: 200,
31+
contentType: 'application/json',
32+
body: JSON.stringify({ id: 'test-id' }),
33+
});
3134
});
32-
});
3335

34-
const requestPromise = waitForErrorRequest(page);
35-
const replayRequestPromise1 = waitForReplayRequest(page, 0);
36+
const requestPromise = waitForErrorRequest(page);
37+
const replayRequestPromise1 = waitForReplayRequest(page, 0);
3638

37-
const url = await getLocalTestPath({ testDir: __dirname });
38-
await page.goto(url);
39+
const url = await getLocalTestPath({ testDir: __dirname });
40+
await page.goto(url);
3941

40-
await page.evaluate(() => {
41-
/* eslint-disable */
42-
fetch('http://localhost:7654/foo', {
43-
method: 'POST',
44-
headers: {
45-
Accept: 'application/json',
46-
'Content-Type': 'application/json',
47-
Cache: 'no-cache',
48-
},
49-
body: '{"foo":"bar"}',
50-
}).then(() => {
51-
// @ts-ignore Sentry is a global
52-
Sentry.captureException('test error');
42+
await page.evaluate(() => {
43+
/* eslint-disable */
44+
fetch('http://localhost:7654/foo', {
45+
method: 'POST',
46+
headers: {
47+
Accept: 'application/json',
48+
'Content-Type': 'application/json',
49+
Cache: 'no-cache',
50+
},
51+
body: 'input body',
52+
}).then(() => {
53+
// @ts-ignore Sentry is a global
54+
Sentry.captureException('test error');
55+
});
56+
/* eslint-enable */
5357
});
54-
/* eslint-enable */
55-
});
5658

57-
const request = await requestPromise;
58-
const eventData = envelopeRequestParser(request);
59+
const request = await requestPromise;
60+
const eventData = envelopeRequestParser(request);
5961

60-
expect(eventData.exception?.values).toHaveLength(1);
62+
expect(eventData.exception?.values).toHaveLength(1);
6163

62-
expect(eventData?.breadcrumbs?.length).toBe(1);
63-
expect(eventData!.breadcrumbs![0]).toEqual({
64-
timestamp: expect.any(Number),
65-
category: 'fetch',
66-
type: 'http',
67-
data: {
68-
method: 'POST',
69-
request_body_size: 13,
70-
response_body_size: 14,
71-
status_code: 200,
72-
url: 'http://localhost:7654/foo',
73-
},
74-
});
75-
76-
const replayReq1 = await replayRequestPromise1;
77-
const { performanceSpans: performanceSpans1 } = getCustomRecordingEvents(replayReq1);
78-
expect(performanceSpans1.filter(span => span.op === 'resource.fetch')).toEqual([
79-
{
64+
expect(eventData?.breadcrumbs?.length).toBe(1);
65+
expect(eventData!.breadcrumbs![0]).toEqual({
66+
timestamp: expect.any(Number),
67+
category: 'fetch',
68+
type: 'http',
8069
data: {
8170
method: 'POST',
82-
statusCode: 200,
83-
request: {
84-
size: 13,
85-
body: '{"foo":"bar"}',
86-
},
87-
response: {
88-
size: 14,
89-
body: '{"res":"this"}',
71+
request_body_size: 10,
72+
response_body_size: 13,
73+
status_code: 200,
74+
url: 'http://localhost:7654/foo',
75+
},
76+
});
77+
78+
const replayReq1 = await replayRequestPromise1;
79+
const { performanceSpans: performanceSpans1 } = getCustomRecordingEvents(replayReq1);
80+
expect(performanceSpans1.filter(span => span.op === 'resource.fetch')).toEqual([
81+
{
82+
data: {
83+
method: 'POST',
84+
statusCode: 200,
85+
request: {
86+
size: 10,
87+
body: 'input body',
88+
},
89+
response: {
90+
size: 13,
91+
body: 'response body',
92+
},
9093
},
94+
description: 'http://localhost:7654/foo',
95+
endTimestamp: expect.any(Number),
96+
op: 'resource.fetch',
97+
startTimestamp: expect.any(Number),
9198
},
92-
description: 'http://localhost:7654/foo',
93-
endTimestamp: expect.any(Number),
94-
op: 'resource.fetch',
95-
startTimestamp: expect.any(Number),
96-
},
97-
]);
98-
});
99+
]);
100+
},
101+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
window.Replay = new Sentry.Replay({
5+
flushMinDelay: 200,
6+
flushMaxDelay: 200,
7+
_experiments: {
8+
captureNetworkBodies: true,
9+
},
10+
});
11+
12+
Sentry.init({
13+
dsn: 'https://[email protected]/1337',
14+
sampleRate: 1,
15+
// We ensure to sample for errors, so by default nothing is sent
16+
replaysSessionSampleRate: 0.0,
17+
replaysOnErrorSampleRate: 1.0,
18+
19+
integrations: [window.Replay],
20+
});
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { expect } from '@playwright/test';
2+
3+
import { sentryTest } from '../../../../../utils/fixtures';
4+
import { envelopeRequestParser, waitForErrorRequest } from '../../../../../utils/helpers';
5+
import {
6+
getCustomRecordingEvents,
7+
shouldSkipReplayTest,
8+
waitForReplayRequest,
9+
} from '../../../../../utils/replayHelpers';
10+
11+
sentryTest(
12+
'captures JSON requestBody & responseBody when experiment is configured',
13+
async ({ getLocalTestPath, page }) => {
14+
if (shouldSkipReplayTest()) {
15+
sentryTest.skip();
16+
}
17+
18+
await page.route('**/foo', route => {
19+
return route.fulfill({
20+
status: 200,
21+
body: JSON.stringify({ res: 'this' }),
22+
headers: {
23+
'Content-Type': 'application/json',
24+
},
25+
});
26+
});
27+
28+
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
29+
return route.fulfill({
30+
status: 200,
31+
contentType: 'application/json',
32+
body: JSON.stringify({ id: 'test-id' }),
33+
});
34+
});
35+
36+
const requestPromise = waitForErrorRequest(page);
37+
const replayRequestPromise1 = waitForReplayRequest(page, 0);
38+
39+
const url = await getLocalTestPath({ testDir: __dirname });
40+
await page.goto(url);
41+
42+
await page.evaluate(() => {
43+
/* eslint-disable */
44+
fetch('http://localhost:7654/foo', {
45+
method: 'POST',
46+
headers: {
47+
Accept: 'application/json',
48+
'Content-Type': 'application/json',
49+
Cache: 'no-cache',
50+
},
51+
body: '{"foo":"bar"}',
52+
}).then(() => {
53+
// @ts-ignore Sentry is a global
54+
Sentry.captureException('test error');
55+
});
56+
/* eslint-enable */
57+
});
58+
59+
const request = await requestPromise;
60+
const eventData = envelopeRequestParser(request);
61+
62+
expect(eventData.exception?.values).toHaveLength(1);
63+
64+
expect(eventData?.breadcrumbs?.length).toBe(1);
65+
expect(eventData!.breadcrumbs![0]).toEqual({
66+
timestamp: expect.any(Number),
67+
category: 'fetch',
68+
type: 'http',
69+
data: {
70+
method: 'POST',
71+
request_body_size: 13,
72+
response_body_size: 14,
73+
status_code: 200,
74+
url: 'http://localhost:7654/foo',
75+
},
76+
});
77+
78+
const replayReq1 = await replayRequestPromise1;
79+
const { performanceSpans: performanceSpans1 } = getCustomRecordingEvents(replayReq1);
80+
expect(performanceSpans1.filter(span => span.op === 'resource.fetch')).toEqual([
81+
{
82+
data: {
83+
method: 'POST',
84+
statusCode: 200,
85+
request: {
86+
size: 13,
87+
body: { foo: 'bar' },
88+
},
89+
response: {
90+
size: 14,
91+
body: { res: 'this' },
92+
},
93+
},
94+
description: 'http://localhost:7654/foo',
95+
endTimestamp: expect.any(Number),
96+
op: 'resource.fetch',
97+
startTimestamp: expect.any(Number),
98+
},
99+
]);
100+
},
101+
);

packages/browser-integration-tests/suites/replay/extendNetworkBreadcrumbs/xhr/captureBodies/test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
} from '../../../../../utils/replayHelpers';
1010

1111
sentryTest(
12-
'captures xhr requestBody & responseBody when experiment is configured',
12+
'captures text xhr requestBody & responseBody when experiment is configured',
1313
async ({ getLocalTestPath, page, browserName }) => {
1414
// These are a bit flaky on non-chromium browsers
1515
if (shouldSkipReplayTest() || browserName !== 'chromium') {
@@ -19,7 +19,7 @@ sentryTest(
1919
await page.route('**/foo', route => {
2020
return route.fulfill({
2121
status: 200,
22-
body: JSON.stringify({ res: 'this' }),
22+
body: 'response body',
2323
headers: {
2424
'Content-Type': 'application/json',
2525
'Content-Length': '',
@@ -49,7 +49,7 @@ sentryTest(
4949
xhr.setRequestHeader('Accept', 'application/json');
5050
xhr.setRequestHeader('Content-Type', 'application/json');
5151
xhr.setRequestHeader('Cache', 'no-cache');
52-
xhr.send('{"foo":"bar"}');
52+
xhr.send('input body');
5353

5454
xhr.addEventListener('readystatechange', function () {
5555
if (xhr.readyState === 4) {
@@ -72,8 +72,8 @@ sentryTest(
7272
type: 'http',
7373
data: {
7474
method: 'POST',
75-
request_body_size: 13,
76-
response_body_size: 14,
75+
request_body_size: 10,
76+
response_body_size: 13,
7777
status_code: 200,
7878
url: 'http://localhost:7654/foo',
7979
},
@@ -86,8 +86,8 @@ sentryTest(
8686
data: {
8787
method: 'POST',
8888
statusCode: 200,
89-
request: { size: 13, body: '{"foo":"bar"}' },
90-
response: { size: 14, body: '{"res":"this"}' },
89+
request: { size: 10, body: 'input body' },
90+
response: { size: 13, body: 'response body' },
9191
},
9292
description: 'http://localhost:7654/foo',
9393
endTimestamp: expect.any(Number),
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
window.Replay = new Sentry.Replay({
5+
flushMinDelay: 200,
6+
flushMaxDelay: 200,
7+
_experiments: {
8+
captureNetworkBodies: true,
9+
},
10+
});
11+
12+
Sentry.init({
13+
dsn: 'https://[email protected]/1337',
14+
sampleRate: 1,
15+
// We ensure to sample for errors, so by default nothing is sent
16+
replaysSessionSampleRate: 0.0,
17+
replaysOnErrorSampleRate: 1.0,
18+
19+
integrations: [window.Replay],
20+
});

0 commit comments

Comments
 (0)