UNPKG

@grafana/faro-core

Version:
296 lines 15.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var initialize_1 = require("../../initialize"); var testUtils_1 = require("../../testUtils"); var transports_1 = require("../../transports"); var apiTestHelpers_1 = require("../apiTestHelpers"); var userAction_1 = __importDefault(require("../userActions/userAction")); var initialize_2 = require("./initialize"); describe('api.exceptions', function () { function createAPI(_a) { var _b = _a === void 0 ? { dedupe: true } : _a, dedupe = _b.dedupe; var transport = new testUtils_1.MockTransport(); var config = (0, testUtils_1.mockConfig)({ dedupe: dedupe, transports: [transport], }); var api = (0, initialize_1.initializeFaro)(config).api; return [api, transport]; } describe('pushError', function () { var api; var transport; beforeEach(function () { var _a; _a = createAPI(), api = _a[0], transport = _a[1]; }); it('error with overrides', function () { var frames = [ { filename: 'foo.js', function: 'FooFn', colno: 4, lineno: 23, }, { filename: 'bar.js', function: 'BarFn', colno: 6, lineno: 52, }, ]; var additionalContext = { message: 'React error boundary', componentStackTrace: 'componentStackTrace', }; api.pushError(new Error('test exception'), { stackFrames: frames, type: 'TestError', context: additionalContext, }); expect(transport.items).toHaveLength(1); var payload = transport.items[0]; expect(payload === null || payload === void 0 ? void 0 : payload.payload).toBeTruthy(); expect(payload === null || payload === void 0 ? void 0 : payload.type).toEqual(transports_1.TransportItemType.EXCEPTION); var evt = payload === null || payload === void 0 ? void 0 : payload.payload; expect(evt.type).toEqual('TestError'); expect(evt.value).toEqual('test exception'); expect(evt.stacktrace).toEqual({ frames: frames }); expect(evt.context).toEqual(additionalContext); }); it('error without overrides', function () { var _a, _b; var err = new Error('test'); api.pushError(err); expect(transport.items).toHaveLength(1); var payload = transport.items[0]; expect((_a = payload === null || payload === void 0 ? void 0 : payload.meta.app) === null || _a === void 0 ? void 0 : _a.name).toEqual('test'); expect(payload === null || payload === void 0 ? void 0 : payload.payload).toBeTruthy(); expect(payload === null || payload === void 0 ? void 0 : payload.type).toEqual(transports_1.TransportItemType.EXCEPTION); var evt = payload === null || payload === void 0 ? void 0 : payload.payload; expect(evt.type).toEqual('Error'); expect(evt.value).toEqual('test'); expect(evt.timestamp).toBeTruthy(); var stacktrace = evt.stacktrace; expect(stacktrace).toBeTruthy(); expect(stacktrace === null || stacktrace === void 0 ? void 0 : stacktrace.frames.length).toBeGreaterThan(3); expect((_b = stacktrace === null || stacktrace === void 0 ? void 0 : stacktrace.frames[0]) === null || _b === void 0 ? void 0 : _b.filename).toEqual('Error: test'); }); it('does not stringify empty context', function () { api.pushError(new Error('test')); api.pushError(new Error('test2'), { context: {}, }); expect(transport.items).toHaveLength(2); expect(transport.items[0].payload.context).toBeUndefined(); expect(transport.items[0].payload.context).toBeUndefined(); }); it('add the original error to the payload', function () { var _a; var transport = new testUtils_1.MockTransport(); var config = (0, testUtils_1.mockConfig)({ transports: [transport], preserveOriginalError: true, }); var api = (0, initialize_1.initializeFaro)(config).api; var error = new Error('test'); api.pushError(error, { originalError: error }); expect(transport.items).toHaveLength(1); expect(((_a = transport.items[0]) === null || _a === void 0 ? void 0 : _a.payload).originalError).toEqual(error); }); describe('Filtering', function () { it('filters the same event', function () { var error = new Error('test'); api.pushError(error); expect(transport.items).toHaveLength(1); api.pushError(error); expect(transport.items).toHaveLength(1); }); it("doesn't filter events with same message and different stacktrace", function () { var error1 = new Error('test'); var error2 = new Error('test'); api.pushError(error1); expect(transport.items).toHaveLength(1); api.pushError(error2); expect(transport.items).toHaveLength(2); }); it("doesn't filter events with other message and same stacktrace", function () { var error = new Error('test'); api.pushError(error); expect(transport.items).toHaveLength(1); error.message = 'test2'; api.pushError(error); expect(transport.items).toHaveLength(2); }); it("doesn't filter events with same message and same stacktrace but different type", function () { var error = new Error('test'); api.pushError(error); expect(transport.items).toHaveLength(1); error.name = 'Another Type'; api.pushError(error); expect(transport.items).toHaveLength(2); }); it("filters an event and doesn't filter the next different one", function () { var error = new Error('test'); api.pushError(error); expect(transport.items).toHaveLength(1); api.pushError(error); expect(transport.items).toHaveLength(1); error.name = 'Another Type'; api.pushError(error); expect(transport.items).toHaveLength(2); }); it("doesn't filter when dedupe is false", function () { var _a; _a = createAPI({ dedupe: false }), api = _a[0], transport = _a[1]; var error = new Error('test'); api.pushError(error); expect(transport.items).toHaveLength(1); api.pushError(error); expect(transport.items).toHaveLength(2); }); it("doesn't filter when skipDedupe is true", function () { var error = new Error('test'); api.pushError(error); expect(transport.items).toHaveLength(1); api.pushError(error, { skipDedupe: true, }); expect(transport.items).toHaveLength(2); }); it("doesn't filter events with same message, same stacktrace, same type but different context", function () { var error = new Error('test'); api.pushError(error, { context: { foo: 'bar' } }); expect(transport.items).toHaveLength(1); api.pushError(error, { context: { bar: 'baz' } }); expect(transport.items).toHaveLength(2); }); it('uses traceId and spanId from custom context', function () { var _a; var spanContext = { traceId: 'my-trace-id', spanId: 'my-span-id', }; var error = new Error('test'); api.pushError(error, { spanContext: spanContext }); expect(transport.items).toHaveLength(1); expect(((_a = transport.items[0]) === null || _a === void 0 ? void 0 : _a.payload).trace).toStrictEqual({ trace_id: 'my-trace-id', span_id: 'my-span-id', }); }); it('Sets the timestamp to the provided custom timestamp', function () { var _a; api.pushEvent('test', undefined, undefined, { timestampOverwriteMs: 123 }); expect(transport.items).toHaveLength(1); expect(((_a = transport.items[0]) === null || _a === void 0 ? void 0 : _a.payload).timestamp).toBe('1970-01-01T00:00:00.123Z'); }); it('Adds error cause to error context', function () { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; var error = new Error('test', { cause: 'foo' }); var error2 = new Error('test2', { cause: [1, 3] }); var error3 = new Error('test3', { cause: { a: 'b' } }); var error4 = new Error('test4', { cause: new Error('original error') }); var error5 = new Error('test5', { cause: null }); var error6 = new Error('test6', { cause: undefined }); var error7 = new Error('test6'); api.pushError(error); api.pushError(error2); api.pushError(error3); api.pushError(error4); api.pushError(error5); api.pushError(error6); api.pushError(error7); expect(transport.items).toHaveLength(7); expect((_b = (_a = transport.items[0]) === null || _a === void 0 ? void 0 : _a.payload) === null || _b === void 0 ? void 0 : _b.context).toEqual({ cause: 'foo' }); expect((_d = (_c = transport.items[1]) === null || _c === void 0 ? void 0 : _c.payload) === null || _d === void 0 ? void 0 : _d.context).toEqual({ cause: '[1,3]' }); expect((_f = (_e = transport.items[2]) === null || _e === void 0 ? void 0 : _e.payload) === null || _f === void 0 ? void 0 : _f.context).toEqual({ cause: '{"a":"b"}' }); expect((_h = (_g = transport.items[3]) === null || _g === void 0 ? void 0 : _g.payload) === null || _h === void 0 ? void 0 : _h.context).toEqual({ cause: 'Error: original error' }); expect((_k = (_j = transport.items[4]) === null || _j === void 0 ? void 0 : _j.payload) === null || _k === void 0 ? void 0 : _k.context).toBeUndefined(); expect((_m = (_l = transport.items[5]) === null || _l === void 0 ? void 0 : _l.payload) === null || _m === void 0 ? void 0 : _m.context).toBeUndefined(); expect((_p = (_o = transport.items[6]) === null || _o === void 0 ? void 0 : _o.payload) === null || _p === void 0 ? void 0 : _p.context).toBeUndefined(); }); it('stringifies all values added to the context', function () { var _a, _b; api.pushError(new Error('Error with context'), { context: { // @ts-expect-error a: 1, b: 'foo', // @ts-expect-error c: true, // @ts-expect-error d: { e: 'bar' }, // @ts-expect-error g: null, // @ts-expect-error h: undefined, // @ts-expect-error i: [1, 2, 3], }, }); var context = (_b = (_a = transport.items[0]) === null || _a === void 0 ? void 0 : _a.payload) === null || _b === void 0 ? void 0 : _b.context; expect(context).toStrictEqual({ a: '1', b: 'foo', c: 'true', d: '{"e":"bar"}', g: 'null', h: 'undefined', i: '[1,2,3]', }); Object.values(context !== null && context !== void 0 ? context : {}).forEach(function (value) { expect(typeof value).toBe('string'); }); }); }); describe('config.ignoreErrors', function () { it('will filter out errors by string or regex', function () { var _a; var transport = new testUtils_1.MockTransport(); var api = (0, initialize_1.initializeFaro)((0, testUtils_1.mockConfig)({ transports: [transport], ignoreErrors: ['Error: ResizeObserver', /FetchError[:\s\w\/]*pwc/, 'chrome-extension://mock-extension-id'], })).api; api.pushError(new Error('Error: ResizeObserver loop limit exceeded')); api.pushError(new Error('FetchError: 404 \n Instantiating https://pwc.grafana.net/public/react-router-dom')); api.pushError(new Error('FetchError: 404 \n Instantiating https://pwc.grafana.net/public/@emotion/css')); var typeErrorMsg = 'TypeError: _.viz is undefined'; api.pushError(new Error(typeErrorMsg)); var mockErrorWithStacktrace = new Error('Mock error for testing'); mockErrorWithStacktrace.name = 'MockError'; mockErrorWithStacktrace.stack = "MockError: Mock error for testing\n at mockFunction (chrome-extension://mock-extension-id/mock-file.js:10:15)\n at anotherFunction (chrome-extension://mock-extension-id/mock-file.js:20:5)\n at Object.<anonymous> (chrome-extension://mock-extension-id/mock-file.js:30:3)"; api.pushError(mockErrorWithStacktrace); expect(transport.items).toHaveLength(1); expect(((_a = transport.items[0]) === null || _a === void 0 ? void 0 : _a.payload).value).toEqual(typeErrorMsg); }); }); }); describe('User action', function () { it('buffers the error if a user action is in progress', function () { var internalLogger = testUtils_1.mockInternalLogger; var config = (0, testUtils_1.mockConfig)(); var api = (0, initialize_2.initializeExceptionsAPI)({ unpatchedConsole: console, internalLogger: internalLogger, config: config, metas: apiTestHelpers_1.mockMetas, transports: apiTestHelpers_1.mockTransports, tracesApi: apiTestHelpers_1.mockTracesApi, userActionsApi: apiTestHelpers_1.mockUserActionsApi, }); apiTestHelpers_1.mockUserActionsApi.getActiveUserAction.mockReturnValueOnce(new userAction_1.default({ name: 'test', trigger: 'foo', transports: apiTestHelpers_1.mockTransports, pushEvent: jest.fn(), })); api.pushError(new Error('test')); expect(apiTestHelpers_1.mockTransports.execute).not.toHaveBeenCalled(); }); }); }); //# sourceMappingURL=initialize.test.js.map