Skip to content

Commit 92d5a6a

Browse files
committed
Remaining fetch tests.
1 parent 325b215 commit 92d5a6a

File tree

3 files changed

+128
-79
lines changed

3 files changed

+128
-79
lines changed

packages/telemetry/browser-telemetry/__tests__/collectors/http/fetch.test.ts

Lines changed: 91 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -48,82 +48,95 @@ describe('given a FetchCollector with a mock recorder', () => {
4848
);
4949
});
5050

51-
// it('stops adding breadcrumbs after unregistering', async () => {
52-
// collector.register(mockRecorder, 'test-session');
53-
// collector.unregister();
54-
55-
// const mockResponse = new Response('test response', { status: 200 });
56-
// window.fetch = jest.fn().mockResolvedValue(mockResponse);
57-
58-
// await fetch('https://api.example.com/data');
59-
60-
// expect(mockRecorder.addBreadcrumb).not.toHaveBeenCalled();
61-
// });
62-
63-
// it('filters URLs based on provided options', async () => {
64-
// const options = {
65-
// urlFilter: (url: string) => url.replace(/token=.*/, 'token=REDACTED'),
66-
// };
67-
68-
// collector = new FetchCollector(options);
69-
// collector.register(mockRecorder, 'test-session');
70-
71-
// const mockResponse = new Response('test response', { status: 200 });
72-
// window.fetch = jest.fn().mockResolvedValue(mockResponse);
73-
74-
// await fetch('https://api.example.com/data?token=secret123');
75-
76-
// expect(mockRecorder.addBreadcrumb).toHaveBeenCalledWith(
77-
// expect.objectContaining<HttpBreadcrumb>({
78-
// data: {
79-
// method: 'GET',
80-
// url: 'https://api.example.com/data?token=REDACTED',
81-
// },
82-
// }),
83-
// );
84-
// });
85-
86-
// it('handles fetch calls with Request objects', async () => {
87-
// collector.register(mockRecorder, 'test-session');
88-
89-
// const mockResponse = new Response('test response', { status: 200 });
90-
// window.fetch = jest.fn().mockResolvedValue(mockResponse);
91-
92-
// const request = new Request('https://api.example.com/data', {
93-
// method: 'PUT',
94-
// body: JSON.stringify({ test: true }),
95-
// });
96-
97-
// await fetch(request);
98-
99-
// expect(mockRecorder.addBreadcrumb).toHaveBeenCalledWith(
100-
// expect.objectContaining<HttpBreadcrumb>({
101-
// message: 'PUT https://api.example.com/data',
102-
// data: {
103-
// method: 'PUT',
104-
// url: 'https://api.example.com/data',
105-
// },
106-
// }),
107-
// );
108-
// });
109-
110-
// it('handles fetch calls with URL objects', async () => {
111-
// collector.register(mockRecorder, 'test-session');
112-
113-
// const mockResponse = new Response('test response', { status: 200 });
114-
// window.fetch = jest.fn().mockResolvedValue(mockResponse);
115-
116-
// const url = new URL('https://api.example.com/data');
117-
// await fetch(url);
118-
119-
// expect(mockRecorder.addBreadcrumb).toHaveBeenCalledWith(
120-
// expect.objectContaining<HttpBreadcrumb>({
121-
// message: 'GET https://api.example.com/data',
122-
// data: {
123-
// method: 'GET',
124-
// url: 'https://api.example.com/data',
125-
// },
126-
// }),
127-
// );
128-
// });
51+
it('stops adding breadcrumbs after unregistering', async () => {
52+
collector.register(mockRecorder, 'test-session');
53+
collector.unregister();
54+
55+
const mockResponse = new Response('test response', { status: 200, statusText: 'OK' });
56+
(initialFetch as jest.Mock).mockResolvedValue(mockResponse);
57+
58+
await fetch('https://api.example.com/data');
59+
60+
expect(mockRecorder.addBreadcrumb).not.toHaveBeenCalled();
61+
});
62+
63+
it('filters URLs based on provided options', async () => {
64+
collector = new FetchCollector({
65+
urlFilters: [(url: string) => url.replace(/token=.*/, 'token=REDACTED')], // Convert urlFilter to urlFilters array
66+
});
67+
collector.register(mockRecorder, 'test-session');
68+
69+
const mockResponse = new Response('test response', { status: 200, statusText: 'OK' });
70+
(initialFetch as jest.Mock).mockResolvedValue(mockResponse);
71+
72+
await fetch('https://api.example.com/data?token=secret123');
73+
74+
expect(mockRecorder.addBreadcrumb).toHaveBeenCalledWith(
75+
expect.objectContaining<HttpBreadcrumb>({
76+
data: {
77+
method: 'GET',
78+
url: 'https://api.example.com/data?token=REDACTED',
79+
statusCode: 200,
80+
statusText: 'OK',
81+
},
82+
class: 'http',
83+
timestamp: expect.any(Number),
84+
level: 'info',
85+
type: 'fetch',
86+
}),
87+
);
88+
});
89+
90+
it('handles fetch calls with Request objects', async () => {
91+
collector.register(mockRecorder, 'test-session');
92+
93+
const mockResponse = new Response('test response', { status: 200, statusText: 'OK' });
94+
(initialFetch as jest.Mock).mockResolvedValue(mockResponse);
95+
96+
const request = new Request('https://api.example.com/data', {
97+
method: 'PUT',
98+
body: JSON.stringify({ test: true }),
99+
});
100+
await fetch(request);
101+
102+
expect(mockRecorder.addBreadcrumb).toHaveBeenCalledWith(
103+
expect.objectContaining<HttpBreadcrumb>({
104+
data: {
105+
method: 'PUT',
106+
url: 'https://api.example.com/data',
107+
statusCode: 200,
108+
statusText: 'OK',
109+
},
110+
class: 'http',
111+
timestamp: expect.any(Number),
112+
level: 'info',
113+
type: 'fetch',
114+
}),
115+
);
116+
});
117+
118+
it('handles fetch calls with URL objects', async () => {
119+
collector.register(mockRecorder, 'test-session');
120+
121+
const mockResponse = new Response('test response', { status: 200, statusText: 'OK' });
122+
(initialFetch as jest.Mock).mockResolvedValue(mockResponse);
123+
124+
const url = new URL('https://api.example.com/data');
125+
await fetch(url);
126+
127+
expect(mockRecorder.addBreadcrumb).toHaveBeenCalledWith(
128+
expect.objectContaining<HttpBreadcrumb>({
129+
data: {
130+
method: 'GET',
131+
url: 'https://api.example.com/data',
132+
statusCode: 200,
133+
statusText: 'OK',
134+
},
135+
class: 'http',
136+
timestamp: expect.any(Number),
137+
level: 'info',
138+
type: 'fetch',
139+
}),
140+
);
141+
});
129142
});

packages/telemetry/browser-telemetry/setup-jest.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,41 @@ Object.defineProperty(global, 'Response', {
3838
configurable: true,
3939
});
4040

41+
// We need a global request to validate the fetch argument processing.
42+
Object.defineProperty(global, 'Request', {
43+
value: class Request {
44+
constructor(input, init = {}) {
45+
this.url = typeof input === 'string' ? input : input.url;
46+
this.method = (init.method || 'GET').toUpperCase();
47+
this.headers = new Map(Object.entries(init.headers || {}));
48+
this.body = init.body || null;
49+
this.mode = init.mode || 'cors';
50+
this.credentials = init.credentials || 'same-origin';
51+
this.cache = init.cache || 'default';
52+
this.redirect = init.redirect || 'follow';
53+
this.referrer = init.referrer || 'about:client';
54+
this.integrity = init.integrity || '';
55+
}
56+
57+
clone() {
58+
return new Request(this.url, {
59+
method: this.method,
60+
headers: Object.fromEntries(this.headers),
61+
body: this.body,
62+
mode: this.mode,
63+
credentials: this.credentials,
64+
cache: this.cache,
65+
redirect: this.redirect,
66+
referrer: this.referrer,
67+
integrity: this.integrity
68+
});
69+
}
70+
},
71+
writable: true,
72+
configurable: true,
73+
});
74+
75+
4176
// Based on:
4277
// https://stackoverflow.com/a/71750830
4378

packages/telemetry/browser-telemetry/src/collectors/http/fetchDecorator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ export function processFetchArgs(
2828
// `instanceof` was not added to Edge until 2015.
2929
if (typeof Request !== 'undefined' && input instanceof Request) {
3030
url = input.url;
31+
method = input.method;
3132
}
32-
if (input instanceof URL) {
33+
if (typeof URL !== 'undefined' && input instanceof URL) {
3334
url = input.toString();
3435
}
3536

0 commit comments

Comments
 (0)