Skip to content

Commit da67dd9

Browse files
committed
add tests for rate limit and custom headers
1 parent 4ef11f0 commit da67dd9

File tree

2 files changed

+56
-11
lines changed

2 files changed

+56
-11
lines changed

packages/browser/src/transports/new-xhr.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,17 @@ import {
77
} from '@sentry/core';
88
import { SyncPromise } from '@sentry/utils';
99

10+
/**
11+
* The DONE ready state for XmlHttpRequest
12+
*
13+
* Defining it here as a constant b/c XMLHttpRequest.DONE is not always defined
14+
* (e.g. during testing, it is `undefined`)
15+
*
16+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState}
17+
*/
18+
const XHR_READYSTATE_DONE = 4;
19+
1020
export interface XHRTransportOptions extends BaseTransportOptions {
11-
// TODO choose whatever is preferred here (I like record more for easier readability)
12-
//headers?: { [key: string]: string };
1321
headers?: Record<string, string>;
1422
}
1523

@@ -22,8 +30,7 @@ export function makeNewXHRTransport(options: XHRTransportOptions): NewTransport
2230
const xhr = new XMLHttpRequest();
2331

2432
xhr.onreadystatechange = (): void => {
25-
// TODO make 4 a constant
26-
if (xhr.readyState === 4) {
33+
if (xhr.readyState === XHR_READYSTATE_DONE) {
2734
const response = {
2835
body: xhr.response,
2936
headers: {
@@ -33,17 +40,18 @@ export function makeNewXHRTransport(options: XHRTransportOptions): NewTransport
3340
reason: xhr.statusText,
3441
statusCode: xhr.status,
3542
};
36-
3743
resolve(response);
3844
}
3945
};
4046

4147
xhr.open('POST', options.url);
48+
4249
for (const header in options.headers) {
4350
if (Object.prototype.hasOwnProperty.call(options.headers, header)) {
4451
xhr.setRequestHeader(header, options.headers[header]);
4552
}
4653
}
54+
4755
xhr.send(request.body);
4856
});
4957
}

packages/browser/test/unit/transports/new-xhr.test.ts

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function createXHRMock() {
2121
status: 200,
2222
response: 'Hello World!',
2323
onreadystatechange: () => {},
24-
getResponseHeader: (header: string) => {
24+
getResponseHeader: jest.fn((header: string) => {
2525
switch (header) {
2626
case 'Retry-After':
2727
return '10';
@@ -30,7 +30,7 @@ function createXHRMock() {
3030
default:
3131
return `${retryAfterSeconds}:error:scope`;
3232
}
33-
},
33+
}),
3434
};
3535

3636
// casting `window` as `any` because XMLHttpRequest is missing in Window (TS-only)
@@ -56,16 +56,53 @@ describe('NewXHRTransport', () => {
5656
expect(xhrMock.setRequestHeader).toHaveBeenCalledTimes(0);
5757
expect(xhrMock.send).toHaveBeenCalledTimes(0);
5858

59+
await Promise.all([transport.send(ERROR_ENVELOPE), (xhrMock as XMLHttpRequest).onreadystatechange(null)]);
60+
61+
expect(xhrMock.open).toHaveBeenCalledTimes(1);
62+
expect(xhrMock.open).toHaveBeenCalledWith('POST', DEFAULT_XHR_TRANSPORT_OPTIONS.url);
63+
expect(xhrMock.send).toHaveBeenCalledTimes(1);
64+
expect(xhrMock.send).toHaveBeenCalledWith(serializeEnvelope(ERROR_ENVELOPE));
65+
});
66+
67+
it('returns the correct response', async () => {
68+
const transport = makeNewXHRTransport(DEFAULT_XHR_TRANSPORT_OPTIONS);
69+
5970
const [res] = await Promise.all([
6071
transport.send(ERROR_ENVELOPE),
6172
(xhrMock as XMLHttpRequest).onreadystatechange(null),
6273
]);
6374

64-
expect(xhrMock.open).toHaveBeenCalledTimes(1);
65-
expect(xhrMock.open).toHaveBeenCalledWith('POST', DEFAULT_XHR_TRANSPORT_OPTIONS.url);
66-
expect(xhrMock.send).toBeCalledWith(serializeEnvelope(ERROR_ENVELOPE));
67-
6875
expect(res).toBeDefined();
6976
expect(res.status).toEqual('success');
7077
});
78+
79+
it('sets rate limit response headers', async () => {
80+
const transport = makeNewXHRTransport(DEFAULT_XHR_TRANSPORT_OPTIONS);
81+
82+
await Promise.all([transport.send(ERROR_ENVELOPE), (xhrMock as XMLHttpRequest).onreadystatechange(null)]);
83+
84+
expect(xhrMock.getResponseHeader).toHaveBeenCalledTimes(2);
85+
expect(xhrMock.getResponseHeader).toHaveBeenCalledWith('X-Sentry-Rate-Limits');
86+
expect(xhrMock.getResponseHeader).toHaveBeenCalledWith('Retry-After');
87+
});
88+
89+
it('sets custom request headers', async () => {
90+
const headers = {
91+
referrerPolicy: 'strict-origin',
92+
keepalive: 'true',
93+
referrer: 'http://example.org',
94+
};
95+
const options: XHRTransportOptions = {
96+
...DEFAULT_XHR_TRANSPORT_OPTIONS,
97+
headers,
98+
};
99+
100+
const transport = makeNewXHRTransport(options);
101+
await Promise.all([transport.send(ERROR_ENVELOPE), (xhrMock as XMLHttpRequest).onreadystatechange(null)]);
102+
103+
expect(xhrMock.setRequestHeader).toHaveBeenCalledTimes(3);
104+
expect(xhrMock.setRequestHeader).toHaveBeenCalledWith('referrerPolicy', headers.referrerPolicy);
105+
expect(xhrMock.setRequestHeader).toHaveBeenCalledWith('keepalive', headers.keepalive);
106+
expect(xhrMock.setRequestHeader).toHaveBeenCalledWith('referrer', headers.referrer);
107+
});
71108
});

0 commit comments

Comments
 (0)