Skip to content

Commit 87e52b5

Browse files
authored
fix(replay): Correct getOutputType to not use non-existent BODY_SKIPPED warning (#84654)
This actually does not exist in our SDK, instead we can make the same assumption using sdk configuration options (e.g. if they have the option enabled) and if the body is empty to determine if we should show the onboarding setup. ref: getsentry/sentry-javascript#7953 (comment) closes: getsentry/sentry-javascript#8004
1 parent c06c34e commit 87e52b5

File tree

5 files changed

+161
-63
lines changed

5 files changed

+161
-63
lines changed

static/app/utils/replays/replayReader.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,8 @@ export default class ReplayReader {
726726

727727
isVideoReplay = () => this.getVideoEvents().length > 0;
728728

729+
isNetworkCaptureBodySetup = () => Boolean(this.getSDKOptions()?.networkCaptureBodies);
730+
729731
isNetworkDetailsSetup = memoize(() => {
730732
const sdkOptions = this.getSDKOptions();
731733
if (sdkOptions) {

static/app/views/replays/detail/network/details/content.spec.tsx

Lines changed: 144 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const [
2323
img,
2424
fetchNoDataObj,
2525
fetchUrlSkipped,
26-
fetchBodySkipped,
26+
fetchEmptyBody,
2727
fetchWithHeaders,
2828
fetchWithRespBody,
2929
] = hydrateSpans(ReplayRecordFixture(), [
@@ -60,13 +60,11 @@ const [
6060
method: 'GET',
6161
statusCode: 200,
6262
request: {
63-
// @ts-expect-error 'BODY_SKIPPED' is not assignable to type NetworkMetaWarning
64-
_meta: {warnings: ['BODY_SKIPPED']},
63+
_meta: {warnings: []},
6564
headers: {accept: 'application/json'},
6665
},
6766
response: {
68-
// @ts-expect-error 'BODY_SKIPPED' is not assignable to type NetworkMetaWarning
69-
_meta: {warnings: ['BODY_SKIPPED']},
67+
_meta: {warnings: []},
7068
headers: {'content-type': 'application/json'},
7169
},
7270
},
@@ -114,7 +112,7 @@ const mockItems = {
114112
img: img!,
115113
fetchNoDataObj: fetchNoDataObj!,
116114
fetchUrlSkipped: fetchUrlSkipped!,
117-
fetchBodySkipped: fetchBodySkipped!,
115+
fetchEmptyBody: fetchEmptyBody!,
118116
fetchWithHeaders: fetchWithHeaders!,
119117
fetchWithRespBody: fetchWithRespBody!,
120118
};
@@ -144,14 +142,17 @@ describe('NetworkDetailsContent', () => {
144142

145143
describe('Unsupported Operation', () => {
146144
it.each([
147-
{isSetup: false, itemName: 'img'},
148-
{isSetup: true, itemName: 'img'},
145+
{isSetup: false, isCaptureBodySetup: true, itemName: 'img'},
146+
{isSetup: true, isCaptureBodySetup: true, itemName: 'img'},
147+
{isSetup: false, isCaptureBodySetup: false, itemName: 'img'},
148+
{isSetup: true, isCaptureBodySetup: false, itemName: 'img'},
149149
])(
150150
'should render the `general` & `unsupported` sections when the span is not FETCH or XHR and isSetup=$isSetup. [$itemName]',
151-
({isSetup}) => {
151+
({isSetup, isCaptureBodySetup}) => {
152152
render(
153153
<NetworkDetailsContent
154154
{...basicSectionProps()}
155+
isCaptureBodySetup={isCaptureBodySetup}
155156
isSetup={isSetup}
156157
item={mockItems.img}
157158
visibleTab={visibleTab}
@@ -169,17 +170,23 @@ describe('NetworkDetailsContent', () => {
169170

170171
describe('Supported Operation', () => {
171172
it.each([
172-
{isSetup: false, itemName: 'fetchNoDataObj'},
173-
{isSetup: false, itemName: 'fetchUrlSkipped'},
174-
{isSetup: false, itemName: 'fetchBodySkipped'},
175-
{isSetup: false, itemName: 'fetchWithHeaders'},
176-
{isSetup: false, itemName: 'fetchWithRespBody'},
173+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchNoDataObj'},
174+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchUrlSkipped'},
175+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchEmptyBody'},
176+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchWithHeaders'},
177+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchWithRespBody'},
178+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchNoDataObj'},
179+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchUrlSkipped'},
180+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchEmptyBody'},
181+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchWithHeaders'},
182+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchWithRespBody'},
177183
])(
178184
'should render the `general` & `setup` sections when isSetup=false, no matter the item. [$itemName]',
179-
({isSetup, itemName}) => {
185+
({isSetup, isCaptureBodySetup, itemName}) => {
180186
render(
181187
<NetworkDetailsContent
182188
{...basicSectionProps()}
189+
isCaptureBodySetup={isCaptureBodySetup}
183190
isSetup={isSetup}
184191
item={mockItems[itemName as keyof typeof mockItems]}
185192
visibleTab={visibleTab}
@@ -195,15 +202,18 @@ describe('NetworkDetailsContent', () => {
195202
);
196203

197204
it.each([
198-
{isSetup: true, itemName: 'fetchNoDataObj'},
199-
{isSetup: true, itemName: 'fetchUrlSkipped'},
205+
{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchNoDataObj'},
206+
{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchUrlSkipped'},
207+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchNoDataObj'},
208+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchUrlSkipped'},
200209
])(
201210
'should render the `general` & `setup` sections when the item has no data. [$itemName]',
202-
({isSetup, itemName}) => {
211+
({isSetup, isCaptureBodySetup, itemName}) => {
203212
render(
204213
<NetworkDetailsContent
205214
{...basicSectionProps()}
206215
isSetup={isSetup}
216+
isCaptureBodySetup={isCaptureBodySetup}
207217
item={mockItems[itemName as keyof typeof mockItems]}
208218
visibleTab={visibleTab}
209219
/>
@@ -218,15 +228,19 @@ describe('NetworkDetailsContent', () => {
218228
);
219229

220230
it.each([
221-
{isSetup: true, itemName: 'fetchBodySkipped'},
222-
{isSetup: true, itemName: 'fetchWithHeaders'},
223-
{isSetup: true, itemName: 'fetchWithRespBody'},
231+
{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchEmptyBody'},
232+
{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchWithHeaders'},
233+
{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchWithRespBody'},
234+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchEmptyBody'},
235+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchWithHeaders'},
236+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchWithRespBody'},
224237
])(
225238
'should render the `general` & two `headers` sections, and always the setup section, when things are setup and the item has some data. [$itemName]',
226-
({isSetup, itemName}) => {
239+
({isSetup, isCaptureBodySetup, itemName}) => {
227240
render(
228241
<NetworkDetailsContent
229242
{...basicSectionProps()}
243+
isCaptureBodySetup={isCaptureBodySetup}
230244
isSetup={isSetup}
231245
item={mockItems[itemName as keyof typeof mockItems]}
232246
visibleTab={visibleTab}
@@ -248,14 +262,17 @@ describe('NetworkDetailsContent', () => {
248262

249263
describe('Unsupported Operation', () => {
250264
it.each([
251-
{isSetup: false, itemName: 'img'},
252-
{isSetup: true, itemName: 'img'},
265+
{isSetup: false, isCaptureBodySetup: true, itemName: 'img'},
266+
{isSetup: true, isCaptureBodySetup: true, itemName: 'img'},
267+
{isSetup: false, isCaptureBodySetup: false, itemName: 'img'},
268+
{isSetup: true, isCaptureBodySetup: false, itemName: 'img'},
253269
])(
254270
'should render the `query params` & `unsupported` sections when the span is not FETCH or XHR and isSetup=$isSetup. [$itemName]',
255-
({isSetup}) => {
271+
({isSetup, isCaptureBodySetup}) => {
256272
render(
257273
<NetworkDetailsContent
258274
{...basicSectionProps()}
275+
isCaptureBodySetup={isCaptureBodySetup}
259276
isSetup={isSetup}
260277
item={mockItems.img}
261278
visibleTab={visibleTab}
@@ -273,17 +290,23 @@ describe('NetworkDetailsContent', () => {
273290

274291
describe('Supported Operation', () => {
275292
it.each([
276-
{isSetup: false, itemName: 'fetchNoDataObj'},
277-
{isSetup: false, itemName: 'fetchUrlSkipped'},
278-
{isSetup: false, itemName: 'fetchBodySkipped'},
279-
{isSetup: false, itemName: 'fetchWithHeaders'},
280-
{isSetup: false, itemName: 'fetchWithRespBody'},
293+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchNoDataObj'},
294+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchUrlSkipped'},
295+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchEmptyBody'},
296+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchWithHeaders'},
297+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchWithRespBody'},
298+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchNoDataObj'},
299+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchUrlSkipped'},
300+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchEmptyBody'},
301+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchWithHeaders'},
302+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchWithRespBody'},
281303
])(
282304
'should render the `query params` & `setup` sections when isSetup is false, no matter the item. [$itemName]',
283-
({isSetup, itemName}) => {
305+
({isSetup, isCaptureBodySetup, itemName}) => {
284306
render(
285307
<NetworkDetailsContent
286308
{...basicSectionProps()}
309+
isCaptureBodySetup={isCaptureBodySetup}
287310
isSetup={isSetup}
288311
item={mockItems[itemName as keyof typeof mockItems]}
289312
visibleTab={visibleTab}
@@ -299,16 +322,20 @@ describe('NetworkDetailsContent', () => {
299322
);
300323

301324
it.each([
302-
{isSetup: true, itemName: 'fetchNoDataObj'},
303-
{isSetup: true, itemName: 'fetchUrlSkipped'},
304-
{isSetup: true, itemName: 'fetchBodySkipped'},
305-
{isSetup: true, itemName: 'fetchWithHeaders'},
325+
{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchNoDataObj'},
326+
{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchUrlSkipped'},
327+
{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchWithHeaders'},
328+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchNoDataObj'},
329+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchUrlSkipped'},
330+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchEmptyBody'},
331+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchWithHeaders'},
306332
])(
307333
'should render the `query params` & `setup` sections when the item has no data. [$itemName]',
308-
({isSetup, itemName}) => {
334+
({isSetup, isCaptureBodySetup, itemName}) => {
309335
render(
310336
<NetworkDetailsContent
311337
{...basicSectionProps()}
338+
isCaptureBodySetup={isCaptureBodySetup}
312339
isSetup={isSetup}
313340
item={mockItems[itemName as keyof typeof mockItems]}
314341
visibleTab={visibleTab}
@@ -323,12 +350,37 @@ describe('NetworkDetailsContent', () => {
323350
}
324351
);
325352

326-
it.each([{isSetup: true, itemName: 'fetchWithRespBody'}])(
353+
it.each([{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchEmptyBody'}])(
354+
'should render an empty `request body` when SDK option to capture network body is setup and the request body is empty.',
355+
({isSetup, isCaptureBodySetup, itemName}) => {
356+
render(
357+
<NetworkDetailsContent
358+
{...basicSectionProps()}
359+
isCaptureBodySetup={isCaptureBodySetup}
360+
isSetup={isSetup}
361+
item={mockItems[itemName as keyof typeof mockItems]}
362+
visibleTab={visibleTab}
363+
/>
364+
);
365+
366+
expect(queryScreenState()).toStrictEqual({
367+
dataSectionHeaders: ['Query String Parameters', 'Request BodySize: 0 B'],
368+
isShowingUnsupported: false,
369+
isShowingSetup: false,
370+
});
371+
}
372+
);
373+
374+
it.each([
375+
{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchWithRespBody'},
376+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchWithRespBody'},
377+
])(
327378
'should render the `query params` & `request payload` sections when things are setup and the item has some data. [$itemName]',
328-
({isSetup, itemName}) => {
379+
({isSetup, isCaptureBodySetup, itemName}) => {
329380
render(
330381
<NetworkDetailsContent
331382
{...basicSectionProps()}
383+
isCaptureBodySetup={isCaptureBodySetup}
332384
isSetup={isSetup}
333385
item={mockItems[itemName as keyof typeof mockItems]}
334386
visibleTab={visibleTab}
@@ -350,14 +402,17 @@ describe('NetworkDetailsContent', () => {
350402

351403
describe('Unsupported Operation', () => {
352404
it.each([
353-
{isSetup: false, itemName: 'img'},
354-
{isSetup: true, itemName: 'img'},
405+
{isSetup: false, isCaptureBodySetup: true, itemName: 'img'},
406+
{isSetup: true, isCaptureBodySetup: true, itemName: 'img'},
407+
{isSetup: false, isCaptureBodySetup: false, itemName: 'img'},
408+
{isSetup: true, isCaptureBodySetup: false, itemName: 'img'},
355409
])(
356410
'should render the `unsupported` section when the span is not FETCH or XHR and isSetup=$isSetup. [$itemName]',
357-
({isSetup}) => {
411+
({isSetup, isCaptureBodySetup}) => {
358412
render(
359413
<NetworkDetailsContent
360414
{...basicSectionProps()}
415+
isCaptureBodySetup={isCaptureBodySetup}
361416
isSetup={isSetup}
362417
item={mockItems.img}
363418
visibleTab={visibleTab}
@@ -375,17 +430,23 @@ describe('NetworkDetailsContent', () => {
375430

376431
describe('Supported Operation', () => {
377432
it.each([
378-
{isSetup: false, itemName: 'fetchNoDataObj'},
379-
{isSetup: false, itemName: 'fetchUrlSkipped'},
380-
{isSetup: false, itemName: 'fetchBodySkipped'},
381-
{isSetup: false, itemName: 'fetchWithHeaders'},
382-
{isSetup: false, itemName: 'fetchWithRespBody'},
433+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchNoDataObj'},
434+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchUrlSkipped'},
435+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchEmptyBody'},
436+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchWithHeaders'},
437+
{isSetup: false, isCaptureBodySetup: true, itemName: 'fetchWithRespBody'},
438+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchNoDataObj'},
439+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchUrlSkipped'},
440+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchEmptyBody'},
441+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchWithHeaders'},
442+
{isSetup: false, isCaptureBodySetup: false, itemName: 'fetchWithRespBody'},
383443
])(
384444
'should render the `setup` section when isSetup is false, no matter the item. [$itemName]',
385-
({isSetup, itemName}) => {
445+
({isSetup, isCaptureBodySetup, itemName}) => {
386446
render(
387447
<NetworkDetailsContent
388448
{...basicSectionProps()}
449+
isCaptureBodySetup={isCaptureBodySetup}
389450
isSetup={isSetup}
390451
item={mockItems[itemName as keyof typeof mockItems]}
391452
visibleTab={visibleTab}
@@ -401,16 +462,20 @@ describe('NetworkDetailsContent', () => {
401462
);
402463

403464
it.each([
404-
{isSetup: true, itemName: 'fetchNoDataObj'},
405-
{isSetup: true, itemName: 'fetchUrlSkipped'},
406-
{isSetup: true, itemName: 'fetchBodySkipped'},
407-
{isSetup: true, itemName: 'fetchWithHeaders'},
465+
{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchNoDataObj'},
466+
{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchUrlSkipped'},
467+
{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchWithHeaders'},
468+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchNoDataObj'},
469+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchUrlSkipped'},
470+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchEmptyBody'},
471+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchWithHeaders'},
408472
])(
409473
'should render the `setup` section when the item has no data. [$itemName]',
410-
({isSetup, itemName}) => {
474+
({isSetup, isCaptureBodySetup, itemName}) => {
411475
render(
412476
<NetworkDetailsContent
413477
{...basicSectionProps()}
478+
isCaptureBodySetup={isCaptureBodySetup}
414479
isSetup={isSetup}
415480
item={mockItems[itemName as keyof typeof mockItems]}
416481
visibleTab={visibleTab}
@@ -425,12 +490,37 @@ describe('NetworkDetailsContent', () => {
425490
}
426491
);
427492

428-
it.each([{isSetup: true, itemName: 'fetchWithRespBody'}])(
493+
it.each([{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchEmptyBody'}])(
494+
'should render an empty `response body` when SDK option to capture network body is setup and the response body is empty.',
495+
({isSetup, isCaptureBodySetup, itemName}) => {
496+
render(
497+
<NetworkDetailsContent
498+
{...basicSectionProps()}
499+
isCaptureBodySetup={isCaptureBodySetup}
500+
isSetup={isSetup}
501+
item={mockItems[itemName as keyof typeof mockItems]}
502+
visibleTab={visibleTab}
503+
/>
504+
);
505+
506+
expect(queryScreenState()).toStrictEqual({
507+
dataSectionHeaders: ['Response BodySize: 0 B'],
508+
isShowingUnsupported: false,
509+
isShowingSetup: false,
510+
});
511+
}
512+
);
513+
514+
it.each([
515+
{isSetup: true, isCaptureBodySetup: true, itemName: 'fetchWithRespBody'},
516+
{isSetup: true, isCaptureBodySetup: false, itemName: 'fetchWithRespBody'},
517+
])(
429518
'should render the `response body` section when things are setup and the item has some data. [$itemName]',
430-
({isSetup, itemName}) => {
519+
({isSetup, isCaptureBodySetup, itemName}) => {
431520
render(
432521
<NetworkDetailsContent
433522
{...basicSectionProps()}
523+
isCaptureBodySetup={isCaptureBodySetup}
434524
isSetup={isSetup}
435525
item={mockItems[itemName as keyof typeof mockItems]}
436526
visibleTab={visibleTab}

0 commit comments

Comments
 (0)