Skip to content

Commit

Permalink
add tests for rate limit and custom headers
Browse files Browse the repository at this point in the history
  • Loading branch information
Lms24 committed Mar 28, 2022
1 parent bc684f2 commit 105abad
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 11 deletions.
18 changes: 13 additions & 5 deletions packages/browser/src/transports/new-xhr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,17 @@ import {
} from '@sentry/core';
import { SyncPromise } from '@sentry/utils';

/**
* The DONE ready state for XmlHttpRequest
*
* Defining it here as a constant b/c XMLHttpRequest.DONE is not always defined
* (e.g. during testing, it is `undefined`)
*
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState}
*/
const XHR_READYSTATE_DONE = 4;

export interface XHRTransportOptions extends BaseTransportOptions {
// TODO choose whatever is preferred here (I like record more for easier readability)
//headers?: { [key: string]: string };
headers?: Record<string, string>;
}

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

xhr.onreadystatechange = (): void => {
// TODO make 4 a constant
if (xhr.readyState === 4) {
if (xhr.readyState === XHR_READYSTATE_DONE) {
const response = {
body: xhr.response,
headers: {
Expand All @@ -33,17 +40,18 @@ export function makeNewXHRTransport(options: XHRTransportOptions): NewTransport
reason: xhr.statusText,
statusCode: xhr.status,
};

resolve(response);
}
};

xhr.open('POST', options.url);

for (const header in options.headers) {
if (Object.prototype.hasOwnProperty.call(options.headers, header)) {
xhr.setRequestHeader(header, options.headers[header]);
}
}

xhr.send(request.body);
});
}
Expand Down
49 changes: 43 additions & 6 deletions packages/browser/test/unit/transports/new-xhr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function createXHRMock() {
status: 200,
response: 'Hello World!',
onreadystatechange: () => {},
getResponseHeader: (header: string) => {
getResponseHeader: jest.fn((header: string) => {
switch (header) {
case 'Retry-After':
return '10';
Expand All @@ -30,7 +30,7 @@ function createXHRMock() {
default:
return `${retryAfterSeconds}:error:scope`;
}
},
}),
};

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

await Promise.all([transport.send(ERROR_ENVELOPE), (xhrMock as XMLHttpRequest).onreadystatechange(null)]);

expect(xhrMock.open).toHaveBeenCalledTimes(1);
expect(xhrMock.open).toHaveBeenCalledWith('POST', DEFAULT_XHR_TRANSPORT_OPTIONS.url);
expect(xhrMock.send).toHaveBeenCalledTimes(1);
expect(xhrMock.send).toHaveBeenCalledWith(serializeEnvelope(ERROR_ENVELOPE));
});

it('returns the correct response', async () => {
const transport = makeNewXHRTransport(DEFAULT_XHR_TRANSPORT_OPTIONS);

const [res] = await Promise.all([
transport.send(ERROR_ENVELOPE),
(xhrMock as XMLHttpRequest).onreadystatechange(null),
]);

expect(xhrMock.open).toHaveBeenCalledTimes(1);
expect(xhrMock.open).toHaveBeenCalledWith('POST', DEFAULT_XHR_TRANSPORT_OPTIONS.url);
expect(xhrMock.send).toBeCalledWith(serializeEnvelope(ERROR_ENVELOPE));

expect(res).toBeDefined();
expect(res.status).toEqual('success');
});

it('sets rate limit response headers', async () => {
const transport = makeNewXHRTransport(DEFAULT_XHR_TRANSPORT_OPTIONS);

await Promise.all([transport.send(ERROR_ENVELOPE), (xhrMock as XMLHttpRequest).onreadystatechange(null)]);

expect(xhrMock.getResponseHeader).toHaveBeenCalledTimes(2);
expect(xhrMock.getResponseHeader).toHaveBeenCalledWith('X-Sentry-Rate-Limits');
expect(xhrMock.getResponseHeader).toHaveBeenCalledWith('Retry-After');
});

it('sets custom request headers', async () => {
const headers = {
referrerPolicy: 'strict-origin',
keepalive: 'true',
referrer: 'http://example.org',
};
const options: XHRTransportOptions = {
...DEFAULT_XHR_TRANSPORT_OPTIONS,
headers,
};

const transport = makeNewXHRTransport(options);
await Promise.all([transport.send(ERROR_ENVELOPE), (xhrMock as XMLHttpRequest).onreadystatechange(null)]);

expect(xhrMock.setRequestHeader).toHaveBeenCalledTimes(3);
expect(xhrMock.setRequestHeader).toHaveBeenCalledWith('referrerPolicy', headers.referrerPolicy);
expect(xhrMock.setRequestHeader).toHaveBeenCalledWith('keepalive', headers.keepalive);
expect(xhrMock.setRequestHeader).toHaveBeenCalledWith('referrer', headers.referrer);
});
});

0 comments on commit 105abad

Please sign in to comment.