8000 feat(replay): Capture fetch body size for replay events (#7524) · GingerAdonis/sentry-javascript@21dd20d · GitHub
[go: up one dir, main page]

Skip to content

Commit 21dd20d

Browse files
authored
feat(replay): Capture fetch body size for replay events (getsentry#7524)
1 parent aca5249 commit 21dd20d

File tree

11 files changed

+455
-41
lines changed

11 files changed

+455
-41
lines changed

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { expect } from '@playwright/test';
22

33
import { sentryTest } from '../../../../../utils/fixtures';
44
import { envelopeRequestParser, waitForErrorRequest } from '../../../../../utils/helpers';
5-
import { shouldSkipReplayTest } from '../../../../../utils/replayHelpers';
5+
import {
6+
getCustomRecordingEvents,
7+
shouldSkipReplayTest,
8+
waitForReplayRequest,
9+
} from '../../../../../utils/replayHelpers';
610

711
sentryTest('parses response_body_size from Content-Length header if available', async ({ getLocalTestPath, page }) => {
812
if (shouldSkipReplayTest()) {
@@ -22,7 +26,17 @@ sentryTest('parses response_body_size from Content-Length header if available',
2226
});
2327
});
2428

29+
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
30+
return route.fulfill({
31+
status: 200,
32+
contentType: 'application/json',
33+
body: JSON.stringify({ id: 'test-id' }),
34+
});
35+
});
36+
2537
const requestPromise = waitForErrorRequest(page);
38+
const replayRequestPromise1 = waitForReplayRequest(page, 0);
39+
2640
const url = await getLocalTestPath({ testDir: __dirname });
2741
await page.goto(url);
2842

@@ -58,4 +72,20 @@ sentryTest('parses response_body_size from Content-Length header if available',
5872
url: 'http://localhost:7654/foo',
5973
},
6074
});
75+
76+
const replayReq1 = await replayRequestPromise1;
77+
const { performanceSpans: performanceSpans1 } = getCustomRecordingEvents(replayReq1);
78+
expect(performanceSpans1.filter(span => span.op === 'resource.fetch')).toEqual([
79+
{
80+
data: {
81+
method: 'GET',
82+
responseBodySize: 789,
83+
statusCode: 200,
84+
},
85+
description: 'http://localhost:7654/foo',
86+
endTimestamp: expect.any(Number),
87+
op: 'resource.fetch',
88+
startTimestamp: expect.any(Number),
89+
},
90+
]);
6191
});

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { expect } from '@playwright/test';
22

33
import { sentryTest } from '../../../../../utils/fixtures';
44
import { envelopeRequestParser, waitForErrorRequest } from '../../../../../utils/helpers';
5-
import { shouldSkipReplayTest } from '../../../../../utils/replayHelpers';
5+
import {
6+
getCustomRecordingEvents,
7+
shouldSkipReplayTest,
8+
waitForReplayRequest,
9+
} from '../../../../../utils/replayHelpers';
610

711
sentryTest('does not capture response_body_size without Content-Length header', async ({ getLocalTestPath, page }) => {
812
if (shouldSkipReplayTest()) {
@@ -22,7 +26,17 @@ sentryTest('does not capture response_body_size without Content-Length header',
2226
});
2327
});
2428

29+
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
30+
return route.fulfill({
31+
status: 200,
32+
contentType: 'application/json',
33+
body: JSON.stringify({ id: 'test-id' }),
34+
});
35+
});
36+
2537
const requestPromise = waitForErrorRequest(page);
38+
const replayRequestPromise1 = waitForReplayRequest(page, 0);
39+
2640
const url = await getLocalTestPath({ testDir: __dirname });
2741
await page.goto(url);
2842

@@ -57,4 +71,20 @@ sentryTest('does not capture response_body_size without Content-Length header',
5771
url: 'http://localhost:7654/foo',
5872
},
5973
});
74+
75+
const replayReq1 = await replayRequestPromise1;
76+
const { performanceSpans: performanceSpans1 } = getCustomRecordingEvents(replayReq1);
77+
expect(performanceSpans1.filter(span => span.op === 'resource.fetch')).toEqual([
78+
{
79+
data: {
80+
method: 'GET',
81+
responseBodySize: 29,
82+
statusCode: 200,
83+
},
84+
description: 'http://localhost:7654/foo',
85+
endTimestamp: expect.any(Number),
86+
op: 'resource.fetch',
87+
startTimestamp: expect.any(Number),
88+
},
89+
]);
6090
});

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { expect } from '@playwright/test';
22

33
import { sentryTest } from '../../../../../utils/fixtures';
44
import { envelopeRequestParser, waitForErrorRequest } from '../../../../../utils/helpers';
5-
import { shouldSkipReplayTest } from '../../../../../utils/replayHelpers';
5+
import {
6+
getCustomRecordingEvents,
7+
shouldSkipReplayTest,
8+
waitForReplayRequest,
9+
} from '../../../../../utils/replayHelpers';
610

711
sentryTest('calculates body sizes for non-string bodies', async ({ getLocalTestPath, page }) => {
812
if (shouldSkipReplayTest()) {
@@ -19,7 +23,17 @@ sentryTest('calculates body sizes for non-string bodies', async ({ getLocalTestP
1923
});
2024
});
2125

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' }),
31+
});
32+
});
33+
2234
const requestPromise = waitForErrorRequest(page);
35+
const replayRequestPromise1 = waitForReplayRequest(page, 0);
36+
2337
const url = await getLocalTestPath({ testDir: __dirname });
2438
await page.goto(url);
2539

@@ -60,4 +74,21 @@ sentryTest('calculates body sizes for non-string bodies', async ({ getLocalTestP
6074
url: 'http://localhost:7654/foo',
6175
},
6276
});
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+
requestBodySize: 26,
85+
responseBodySize: 24,
86+
statusCode: 200,
87+
},
88+
description: 'http://localhost:7654/foo',
89+
endTimestamp: expect.any(Number),
90+
op: 'resource.fetch',
91+
startTimestamp: expect.any(Number),
92+
},
93+
]);
6394
});

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

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { expect } from '@playwright/test';
22

33
import { sentryTest } from '../../../../../utils/fixtures';
44
import { envelopeRequestParser, waitForErrorRequest } from '../../../../../utils/helpers';
5-
import { shouldSkipReplayTest } from '../../../../../utils/replayHelpers';
5+
import {
6+
getCustomRecordingEvents,
7+
shouldSkipReplayTest,
8+
waitForReplayRequest,
9+
} from '../../../../../utils/replayHelpers';
610

711
sentryTest('captures request_body_size when body is sent', async ({ getLocalTestPath, page }) => {
812
if (shouldSkipReplayTest()) {
@@ -12,16 +16,23 @@ sentryTest('captures request_body_size when body is sent', async ({ getLocalTest
1216
await page.route('**/foo', route => {
1317
return route.fulfill({
1418
status: 200,
15-
body: JSON.stringify({
16-
userNames: ['John', 'Jane'],
17-
}),
1819
headers: {
1920
'Content-Type': 'application/json',
2021
},
2122
});
2223
});
2324

25+
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
26+
return route.fulfill({
27+
status: 200,
28+
contentType: 'application/json',
29+
body: JSON.stringify({ id: 'test-id' }),
30+
});
31+
});
32+
2433
const requestPromise = waitForErrorRequest(page);
34+
const replayRequestPromise1 = waitForReplayRequest(page, 0);
35+
2536
const url = await getLocalTestPath({ testDir: __dirname });
2637
await page.goto(url);
2738

@@ -48,5 +59,32 @@ sentryTest('captures request_body_size when body is sent', async ({ getLocalTest
4859
expect(eventData.exception?.values).toHaveLength(1);
4960

5061
expect(eventData?.breadcrumbs?.length).toBe(1);
62+
expect(eventData!.breadcrumbs![0]).toEqual({
63+
timestamp: expect.any(Number),
64+
category: 'fetch',
65+
type: 'http',
66+
data: {
67+
method: 'POST',
68+
request_body_size: 13,
69+
status_code: 200,
70+
url: 'http://localhost:7654/foo',
71+
},
72+
});
5173
expect(eventData!.breadcrumbs![0].data!.request_body_size).toEqual(13);
74+
75+
const replayReq1 = await replayRequestPromise1;
76+
const { performanceSpans: performanceSpans1 } = getCustomRecordingEvents(replayReq1);
77+
expect(performanceSpans1.filter(span => span.op === 'resource.fetch')).toEqual([
78+
{
79+
data: {
80+
method: 'POST',
81+
requestBodySize: 13,
82+
statusCode: 200,
83+
},
84+
description: 'http://localhost:7654/foo',
85+
endTimestamp: expect.any(Number),
86+
op: 'resource.fetch',
87+
startTimestamp: expect.any(Number),
88+
},
89+
]);
5290
});

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { expect } from '@playwright/test';
22

33
import { sentryTest } from '../../../../../utils/fixtures';
44
import { envelopeRequestParser, waitForErrorRequest } from '../../../../../utils/helpers';
5-
import { shouldSkipReplayTest } from '../../../../../utils/replayHelpers';
5+
import {
6+
getCustomRecordingEvents,
7+
shouldSkipReplayTest,
8+
waitForReplayRequest,
9+
} from '../../../../../utils/replayHelpers';
610

711
sentryTest(
812
'parses response_body_size from Content-Length header if available',
@@ -25,7 +29,17 @@ sentryTest(
2529
});
2630
});
2731

32+
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
33+
return route.fulfill({
34+
status: 200,
35+
contentType: 'application/json',
36+
body: JSON.stringify({ id: 'test-id' }),
37+
});
38+
});
39+
2840
const requestPromise = waitForErrorRequest(page);
41+
const replayRequestPromise1 = waitForReplayRequest(page, 0);
42+
2943
const url = await getLocalTestPath({ testDir: __dirname });
3044
await page.goto(url);
3145

@@ -65,5 +79,21 @@ sentryTest(
6579
url: 'http://localhost:7654/foo',
6680
},
6781
});
82+
83+
const replayReq1 = await replayRequestPromise1;
84+
const { performanceSpans: performanceSpans1 } = getCustomRecordingEvents(replayReq1);
85+
expect(performanceSpans1.filter(span => span.op === 'resource.xhr')).toEqual([
86+
{
87+
data: {
88+
method: 'GET',
89+
responseBodySize: 789,
90+
statusCode: 200,
91+
},
92+
description: 'http://localhost:7654/foo',
93+
endTimestamp: expect.any(Number),
94+
op: 'resource.xhr',
95+
startTimestamp: expect.any(Number),
96+
},
97+
]);
6898
},
6999
);

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { expect } from '@playwright/test';
22

33
import { sentryTest } from '../../../../../utils/fixtures';
44
import { envelopeRequestParser, waitForErrorRequest } from '../../../../../utils/helpers';
5-
import { shouldSkipReplayTest } from '../../../../../utils/replayHelpers';
5+
import {
6+
getCustomRecordingEvents,
7+
shouldSkipReplayTest,
8+
waitForReplayRequest,
9+
} from '../../../../../utils/replayHelpers';
610

711
sentryTest(
812
'captures response_body_size without Content-Length header',
@@ -25,7 +29,17 @@ sentryTest(
2529
});
2630
});
2731

32+
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
33+
return route.fulfill({
34+
status: 200,
35+
contentType: 'application/json',
36+
body: JSON.stringify({ id: 'test-id' }),
37+
});
38+
});
39+
2840
const requestPromise = waitForErrorRequest(page);
41+
const replayRequestPromise1 = waitForReplayRequest(page, 0);
42+
2943
const url = await getLocalTestPath({ testDir: __dirname });
3044
await page.goto(url);
3145

@@ -65,5 +79,21 @@ sentryTest(
6579
url: 'http://localhost:7654/foo',
6680
},
6781
});
82+
83+
const replayReq1 = await replayRequestPromise1;
84+
const { performanceSpans: performanceSpans1 } = getCustomRecordingEvents(replayReq1);
85+
expect(performanceSpans1.filter(span => span.op === 'resource.xhr')).toEqual([
86+
{
87+
data: {
88+
method: 'GET',
89+
responseBodySize: 29,
90+
statusCode: 200,
91+
},
92+
description: 'http://localhost:7654/foo',
93+
endTimestamp: expect.any(Number),
94+
op: 'resource.xhr',
95+
startTimestamp: expect.any(Number),
96+
},
97+
]);
6898
},
6999
);

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { expect } from '@playwright/test';
22

33
import { sentryTest } from '../../../../../utils/fixtures';
44
import { envelopeRequestParser, waitForErrorRequest } from '../../../../../utils/helpers';
5-
import { shouldSkipReplayTest } from '../../../../../utils/replayHelpers';
5+
import {
6+
getCustomRecordingEvents,
7+
shouldSkipReplayTest,
8+
waitForReplayRequest,
9+
} from '../../../../../utils/replayHelpers';
610

711
sentryTest('calculates body sizes for non-string bodies', async ({ getLocalTestPath, page, browserName }) => {
812
// These are a bit flaky on non-chromium browsers
@@ -20,7 +24,17 @@ sentryTest('calculates body sizes for non-string bodies', async ({ getLocalTestP
2024
});
2125
});
2226

27+
await page.route('https://dsn.ingest.sentry.io/**/*', route => {
28+
return route.fulfill({
29+
status: 200,
30+
contentType: 'application/json',
31+
body: JSON.stringify({ id: 'test-id' }),
32+
});
33+
});
34+
2335
const requestPromise = waitForErrorRequest(page);
36+
const replayRequestPromise1 = waitForReplayRequest(page, 0);
37+
2438
const url = await getLocalTestPath({ testDir: __dirname });
2539
await page.goto(url);
2640

@@ -63,4 +77,21 @@ sentryTest('calculates body sizes for non-string bodies', async ({ getLocalTestP
6377
url: 'http://localhost:7654/foo',
6478
},
6579
});
80+
81+
const replayReq1 = await replayRequestPromise1;
82+
const { performanceSpans: performanceSpans1 } = getCustomRecordingEvents(replayReq1);
83+
expect(performanceSpans1.filter(span => span.op === 'resource.xhr')).toEqual([
84+
{
85+
data: {
86+
method: 'POST',
87+
requestBodySize: 26,
88+
responseBodySize: 24,
89+
statusCode: 200,
90+
},
91+
description: 'http://localhost:7654/foo',
92+
endTimestamp: expect.any(Number),
93+
op: 'resource.xhr',
94+
startTimestamp: expect.any(Number),
95+
},
96+
]);
6697
});

0 commit comments

Comments
 (0)
0