Files
2024-02-15 17:01:50 +00:00

224 lines
6.5 KiB
TypeScript

import * as Sentry from '@sentry/react';
import {ERROR_MAP as origErrorMap} from 'sentry/utils/requestError/requestError';
import {
addEndpointTagToRequestError,
initializeSdk,
isEventWithFileUrl,
isFilteredRequestErrorEvent,
} from './initializeSdk';
const ERROR_MAP = {
...origErrorMap,
// remove `UndefinedResponseBodyError` since we don't filter those
200: undefined,
};
describe('initializeSdk', () => {
beforeAll(() => {
window.__initialData = {
...window.__initialData,
customerDomain: null,
};
});
// This is a regression test for Sentry incident inc-433
// We need to make sure that /^\// is included in the list of tracePropagationTargets
// so that we can have frontend to backend tracing.
it('enables distributed tracing to sentry api endpoint', () => {
initializeSdk({
...window.__initialData,
apmSampling: 1,
sentryConfig: {
allowUrls: [],
dsn: '',
release: '',
tracePropagationTargets: ['other', 'stuff'],
},
});
expect(Sentry.init).toHaveBeenCalledWith(
expect.objectContaining({
tracePropagationTargets: expect.arrayContaining([/^\//]),
})
);
});
});
describe('isFilteredRequestErrorEvent', () => {
const methods = ['GET', 'POST', 'PUT', 'DELETE'];
const stati = [200, 400, 401, 403, 404, 429];
describe('matching error type, matching message', () => {
for (const method of methods) {
describe(`${method} requests`, () => {
for (const status of stati) {
// We have to filter out falsy values here because 200 isn't in `ERROR_MAP`
// and will never appear with any other error name besides `RequestError`
for (const errorName of ['RequestError', ERROR_MAP[status]].filter(Boolean)) {
describe('main error', () => {
it(`recognizes ${status} ${method} events of type ${errorName}`, () => {
const event = {
exception: {
values: [
{type: errorName, value: `${method} /dogs/are/great/ ${status}`},
],
},
};
expect(isFilteredRequestErrorEvent(event)).toBeTruthy();
});
});
describe('cause error', () => {
it(`recognizes ${status} ${method} events of type ${errorName} as causes`, () => {
const event = {
exception: {
values: [
{type: errorName, value: `${method} /dogs/are/great/ ${status}`},
{type: 'InsufficientTreatsError', value: 'Not enough treats!'},
],
},
};
expect(isFilteredRequestErrorEvent(event)).toBeTruthy();
});
});
}
}
});
}
});
describe('matching error type, non-matching message', () => {
for (const status of stati) {
// We have to filter out falsy values here because 200 isn't in `ERROR_MAP`
// and will never appear with any other error name besides `RequestError`
for (const errorName of ['RequestError', ERROR_MAP[status]].filter(Boolean)) {
describe('main error', () => {
it(`rejects other errors of type ${errorName}`, () => {
const event = {
exception: {
values: [
{type: errorName, value: "Failed to fetch requested object: 'ball'"},
],
},
};
expect(isFilteredRequestErrorEvent(event)).toBeFalsy();
});
});
describe('cause error', () => {
it(`rejects other errors of type ${errorName} as causes`, () => {
const event = {
exception: {
values: [
{type: errorName, value: "Failed to fetch requested object: 'ball'"},
{type: 'InsufficientTreatsError', value: 'Not enough treats!'},
],
},
};
expect(isFilteredRequestErrorEvent(event)).toBeFalsy();
});
});
}
}
});
describe('non-matching error type, non-matching message', () => {
it(`rejects other errors`, () => {
const event = {
exception: {
values: [{type: 'UncaughtSquirrelError', value: 'Squirrel was not caught'}],
},
};
expect(isFilteredRequestErrorEvent(event)).toBeFalsy();
});
it(`rejects other errors as causes`, () => {
const event = {
exception: {
values: [
{type: 'UncaughtSquirrelError', value: 'Squirrel was not caught'},
{type: 'InsufficientTreatsError', value: 'Not enough treats!'},
],
},
};
expect(isFilteredRequestErrorEvent(event)).toBeFalsy();
});
});
});
describe('isEventWithFileUrl', () => {
it('recognizes events with `file://` urls', () => {
const event = {request: {url: 'file://dogs/are/great.html'}};
expect(isEventWithFileUrl(event)).toBeTruthy();
});
it('rejects events with other urls', () => {
const event = {request: {url: 'http://dogs.are.great'}};
expect(isEventWithFileUrl(event)).toBeFalsy();
});
it('rejects events without urls', () => {
const event = {};
expect(isEventWithFileUrl(event)).toBeFalsy();
});
});
describe('addEndpointTagToRequestError', () => {
it('adds `endpoint` tag to events with matching message`', () => {
const event = {
exception: {
values: [{type: 'RequestError', value: 'GET /dogs/are/great/ 500'}],
},
tags: {},
};
addEndpointTagToRequestError(event);
expect(event.tags).toEqual({
endpoint: 'GET /dogs/are/great/',
});
});
it("doesn't add `endpoint` tag to events with non-matching message", () => {
const nonmatchingMessages = [
'RequestError with no endpoint for some reason',
'Some other stuff is wrong with endpoint /dogs/are/great/',
'This error has nothing to do with requests or endpoints at all',
];
for (const msg of nonmatchingMessages) {
const event = {
exception: {
values: [{type: 'RequestError', value: msg}],
},
tags: {},
};
addEndpointTagToRequestError(event);
expect(event.tags).toEqual({});
}
});
it("doesn't add `endpoint` tag to events with no exception", () => {
const event = {
tags: {},
};
addEndpointTagToRequestError(event);
expect(event.tags).toEqual({});
});
});