Skip to content

Commit

Permalink
add further warning & tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mydea committed Dec 4, 2023
1 parent 5f65bbe commit 82f8154
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 116 deletions.
6 changes: 5 additions & 1 deletion packages/replay/src/coreHandlers/util/networkUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,18 @@ export function getBodyString(body: unknown): [string | undefined, NetworkMetaWa
if (body instanceof FormData) {
return [_serializeFormData(body)];
}

if (!body) {
return [undefined];
}
} catch {
DEBUG_BUILD && logger.warn('[Replay] Failed to serialize body', body);
return [undefined, 'BODY_PARSE_ERROR'];
}

DEBUG_BUILD && logger.info('[Replay] Skipping network body because of body type', body);

return [undefined];
return [undefined, 'UNPARSEABLE_BODY_TYPE'];
}

/** Merge a warning into an existing network request/response. */
Expand Down
9 changes: 7 additions & 2 deletions packages/replay/src/coreHandlers/util/xhrUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,13 @@ function _getXhrResponseBody(xhr: XMLHttpRequest): [string | undefined, NetworkM
* Blob
* Document
* POJO
*
* Exported only for tests.
*/
export function _parseXhrResponse(
body: XMLHttpRequest['response'],
responseType: XMLHttpRequest['responseType'],
): [string | undefined, NetworkMetaWarning?] {
logger.log(body, responseType, typeof body);
try {
if (typeof body === 'string') {
return [body];
Expand All @@ -190,14 +191,18 @@ export function _parseXhrResponse(
if (responseType === 'json' && body && typeof body === 'object') {
return [JSON.stringify(body)];
}

if (!body) {
return [undefined];
}
} catch {
__DEBUG_BUILD__ && logger.warn('[Replay] Failed to serialize body', body);
return [undefined, 'BODY_PARSE_ERROR'];
}

__DEBUG_BUILD__ && logger.info('[Replay] Skipping network body because of body type', body);

return [undefined];
return [undefined, 'UNPARSEABLE_BODY_TYPE'];
}

function _getBodySize(
Expand Down
7 changes: 6 additions & 1 deletion packages/replay/src/types/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ type JsonArray = unknown[];

export type NetworkBody = JsonObject | JsonArray | string;

export type NetworkMetaWarning = 'MAYBE_JSON_TRUNCATED' | 'TEXT_TRUNCATED' | 'URL_SKIPPED' | 'BODY_PARSE_ERROR';
export type NetworkMetaWarning =
| 'MAYBE_JSON_TRUNCATED'
| 'TEXT_TRUNCATED'
| 'URL_SKIPPED'
| 'BODY_PARSE_ERROR'
| 'UNPARSEABLE_BODY_TYPE';

interface NetworkMeta {
warnings?: NetworkMetaWarning[];
Expand Down
226 changes: 114 additions & 112 deletions packages/replay/test/unit/coreHandlers/util/fetchUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,136 +2,138 @@ import { TextEncoder } from 'util';

import { _getResponseInfo } from '../../../../src/coreHandlers/util/fetchUtils';

describe('_getResponseInfo', () => {
it('works with captureDetails: false', async () => {
const res = await _getResponseInfo(
false,
{
networkCaptureBodies: true,
textEncoder: new TextEncoder(),
networkResponseHeaders: [],
},
undefined,
undefined,
);
describe('Unit | coreHandlers | util | fetchUtils', () => {
describe('_getResponseInfo', () => {
it('works with captureDetails: false', async () => {
const res = await _getResponseInfo(
false,
{
networkCaptureBodies: true,
textEncoder: new TextEncoder(),
networkResponseHeaders: [],
},
undefined,
undefined,
);

expect(res).toEqual(undefined);
});
expect(res).toEqual(undefined);
});

it('works with captureDetails: false & responseBodySize', async () => {
const res = await _getResponseInfo(
false,
{
networkCaptureBodies: true,
textEncoder: new TextEncoder(),
networkResponseHeaders: [],
},
undefined,
123,
);
it('works with captureDetails: false & responseBodySize', async () => {
const res = await _getResponseInfo(
false,
{
networkCaptureBodies: true,
textEncoder: new TextEncoder(),
networkResponseHeaders: [],
},
undefined,
123,
);

expect(res).toEqual({
headers: {},
size: 123,
_meta: {
warnings: ['URL_SKIPPED'],
},
expect(res).toEqual({
headers: {},
size: 123,
_meta: {
warnings: ['URL_SKIPPED'],
},
});
});
});

it('works with text body', async () => {
const response = {
headers: {
has: () => {
return false;
},
get: () => {
return undefined;
it('works with text body', async () => {
const response = {
headers: {
has: () => {
return false;
},
get: () => {
return undefined;
},
},
},
clone: () => response,
text: () => Promise.resolve('text body'),
} as unknown as Response;
clone: () => response,
text: () => Promise.resolve('text body'),
} as unknown as Response;

const res = await _getResponseInfo(
true,
{
networkCaptureBodies: true,
textEncoder: new TextEncoder(),
networkResponseHeaders: [],
},
response,
undefined,
);
const res = await _getResponseInfo(
true,
{
networkCaptureBodies: true,
textEncoder: new TextEncoder(),
networkResponseHeaders: [],
},
response,
undefined,
);

expect(res).toEqual({
headers: {},
size: 9,
body: 'text body',
expect(res).toEqual({
headers: {},
size: 9,
body: 'text body',
});
});
});

it('works with body that fails', async () => {
const response = {
headers: {
has: () => {
return false;
it('works with body that fails', async () => {
const response = {
headers: {
has: () => {
return false;
},
get: () => {
return undefined;
},
},
get: () => {
return undefined;
},
},
clone: () => response,
text: () => Promise.reject('cannot read'),
} as unknown as Response;
clone: () => response,
text: () => Promise.reject('cannot read'),
} as unknown as Response;

const res = await _getResponseInfo(
true,
{
networkCaptureBodies: true,
textEncoder: new TextEncoder(),
networkResponseHeaders: [],
},
response,
undefined,
);
const res = await _getResponseInfo(
true,
{
networkCaptureBodies: true,
textEncoder: new TextEncoder(),
networkResponseHeaders: [],
},
response,
undefined,
);

expect(res).toEqual({
_meta: { warnings: ['BODY_PARSE_ERROR'] },
headers: {},
size: undefined,
expect(res).toEqual({
_meta: { warnings: ['BODY_PARSE_ERROR'] },
headers: {},
size: undefined,
});
});
});

it('works with body that times out', async () => {
const response = {
headers: {
has: () => {
return false;
},
get: () => {
return undefined;
it('works with body that times out', async () => {
const response = {
headers: {
has: () => {
return false;
},
get: () => {
return undefined;
},
},
},
clone: () => response,
text: () => new Promise(resolve => setTimeout(() => resolve('text body'), 1000)),
} as unknown as Response;
clone: () => response,
text: () => new Promise(resolve => setTimeout(() => resolve('text body'), 1000)),
} as unknown as Response;

const res = await _getResponseInfo(
true,
{
networkCaptureBodies: true,
textEncoder: new TextEncoder(),
networkResponseHeaders: [],
},
response,
undefined,
);
const res = await _getResponseInfo(
true,
{
networkCaptureBodies: true,
textEncoder: new TextEncoder(),
networkResponseHeaders: [],
},
response,
undefined,
);

expect(res).toEqual({
_meta: { warnings: ['BODY_PARSE_ERROR'] },
headers: {},
size: undefined,
expect(res).toEqual({
_meta: { warnings: ['BODY_PARSE_ERROR'] },
headers: {},
size: undefined,
});
});
});
});
36 changes: 36 additions & 0 deletions packages/replay/test/unit/coreHandlers/util/networkUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { NETWORK_BODY_MAX_SIZE } from '../../../../src/constants';
import {
buildNetworkRequestOrResponse,
getBodySize,
getBodyString,
getFullUrl,
parseContentLengthHeader,
} from '../../../../src/coreHandlers/util/networkUtils';
Expand Down Expand Up @@ -248,4 +249,39 @@ describe('Unit | coreHandlers | util | networkUtils', () => {
expect(actual).toBe(expected);
});
});

describe('getBodyString', () => {
it('works with a string', () => {
const actual = getBodyString('abc');
expect(actual).toEqual(['abc']);
});

it('works with URLSearchParams', () => {
const body = new URLSearchParams();
body.append('name', 'Anne');
body.append('age', '32');
const actual = getBodyString(body);
expect(actual).toEqual(['name=Anne&age=32']);
});

it('works with FormData', () => {
const body = new FormData();
body.append('name', 'Anne');
body.append('age', '32');
const actual = getBodyString(body);
expect(actual).toEqual(['name=Anne&age=32']);
});

it('works with empty data', () => {
const body = undefined;
const actual = getBodyString(body);
expect(actual).toEqual([undefined]);
});

it('works with other type of data', () => {
const body = {};
const actual = getBodyString(body);
expect(actual).toEqual([undefined, 'UNPARSEABLE_BODY_TYPE']);
});
});
});

0 comments on commit 82f8154

Please sign in to comment.