import type { RumEvent, RumEventDomainContext } from '@datadog/browser-rum'; import { type Mutable } from '../__mocks__'; import { buildBeforeSend } from '../build-before-send'; import { enrichEvent } from '../enrich-event'; import { handleResource } from '../handle-resource'; import type { State } from '../types'; jest.mock('../enrich-event'); jest.mock('../handle-resource'); describe(`[datadog-rum] ${buildBeforeSend.name}`, () => { const service = 'task-hub'; let state: State; let event: Mutable; let context: RumEventDomainContext; let serviceHandler: jest.Mock; let applicationBeforeSend: jest.Mock; function makeEvent(overrides: Record = {}) { return { type: 'error', service, ...overrides } as unknown as Mutable; } beforeEach(() => { jest.clearAllMocks(); jest.mocked(enrichEvent).mockImplementation(jest.fn()); jest.mocked(handleResource).mockImplementation(jest.fn()); serviceHandler = jest.fn(() => {}); applicationBeforeSend = jest.fn(() => true); state = { services: new Map(), applicationBeforeSend }; state.services.set(service, { beforeSend: serviceHandler }); event = makeEvent(); context = {}; }); const subject = () => buildBeforeSend(state)(event as RumEvent, context); function itReturns(value: boolean) { test(`returns ${value}`, () => { expect(subject()).toBe(value); }); } function itCallsServiceHandler() { test('calls service handler', () => { subject(); expect(serviceHandler).toHaveBeenCalledWith(event, context); }); } function itDoesNotCallServiceHandler() { test('does not call service handler', () => { subject(); expect(serviceHandler).not.toHaveBeenCalled(); }); } test('enriches the event', () => { subject(); expect(enrichEvent).toHaveBeenCalledWith(event, context); }); test('calls application handler', () => { subject(); expect(applicationBeforeSend).toHaveBeenCalledWith(event, context); }); itCallsServiceHandler(); itReturns(true); describe('when enrichment throws', () => { beforeEach(() => { jest.mocked(enrichEvent).mockImplementation(() => { throw new Error('boom'); }); }); itReturns(true); }); describe('when application handler throws', () => { beforeEach(() => { jest.mocked(applicationBeforeSend).mockImplementation(() => { throw new Error('Nope!'); }); }); itCallsServiceHandler(); itReturns(true); }); describe('when service handler throws', () => { beforeEach(() => { jest.mocked(serviceHandler).mockImplementation(() => { throw new Error('Nope!'); }); }); itReturns(true); }); test('does not call handleResource', () => { subject(); expect(handleResource).not.toHaveBeenCalled(); }); describe('when application handler returns false', () => { beforeEach(() => jest.mocked(applicationBeforeSend).mockReturnValue(false)); itReturns(false); itDoesNotCallServiceHandler(); }); describe('when service handler returns false', () => { beforeEach(() => jest.mocked(serviceHandler).mockReturnValue(false)); itReturns(true); }); describe('when event.service does not match', () => { beforeEach(() => (event.service = 'unknown')); itDoesNotCallServiceHandler(); }); describe('when event.service is undefined', () => { beforeEach(() => delete event.service); itDoesNotCallServiceHandler(); }); describe('with a service context', () => { const serviceContext = { orgId: '42', env: 'prod' }; beforeEach(() => (state.services.get(service)!.context = serviceContext)); test('adds context to event', () => { subject(); expect(event.context).toEqual(serviceContext); }); describe('when event.service does not match', () => { beforeEach(() => (event.service = 'unknown')); test('does not add context', () => { subject(); expect(event.context).toBeUndefined(); }); }); describe('with pre-existing event.context', () => { const eventContext = { foo: 'bar' }; beforeEach(() => (event.context = eventContext)); test('merges service and event contexts', () => { subject(); expect(event.context).toEqual({ ...eventContext, ...serviceContext }); }); }); }); describe('with a "resource" event', () => { beforeEach(() => (event = makeEvent({ type: 'resource' }))); test('calls handleResource with the event and context', () => { subject(); expect(handleResource).toHaveBeenCalledWith(event, context); }); describe('when handleResource throws', () => { beforeEach(() => { jest.mocked(handleResource).mockImplementation(() => { throw new Error('Nope!'); }); }); itReturns(true); }); }); });