UNPKG

posthog-node

Version:
165 lines (146 loc) 4.78 kB
// import { PostHog } from '../' import { PostHog as PostHog } from '../../src/posthog-node' import { PostHogSentryIntegration } from '../../src/extensions/sentry-integration' jest.mock('../../src/fetch') import fetch from '../../src/fetch' import { waitForPromises } from 'posthog-core/test/test-utils/test-utils' jest.mock('../../package.json', () => ({ version: '1.2.3' })) const mockedFetch = jest.mocked(fetch, true) const getLastBatchEvents = (): any[] | undefined => { expect(mockedFetch).toHaveBeenCalledWith('http://example.com/batch/', expect.objectContaining({ method: 'POST' })) // reverse mock calls array to get the last call const call = mockedFetch.mock.calls.reverse().find((x) => (x[0] as string).includes('/batch/')) if (!call) { return undefined } return JSON.parse((call[1] as any).body as any).batch } const createMockSentryException = (): any => ({ exception: { values: [ { type: 'Error', value: 'example error', stacktrace: { frames: [], }, mechanism: { type: 'generic', handled: true }, }, ], }, event_id: '80a7023ac32c47f7acb0adaed600d149', platform: 'node', contexts: {}, server_name: 'localhost', timestamp: 1704203482.356, environment: 'production', level: 'error', tags: { posthog_distinct_id: 'EXAMPLE_APP_GLOBAL' }, breadcrumbs: [ { timestamp: 1704203481.422, category: 'console', level: 'log', message: '⚡: Server is running at http://localhost:8010', }, { timestamp: 1704203481.658, category: 'console', level: 'log', message: "PostHog Debug error [ClientError: Your personalApiKey is invalid. Are you sure you're not using your Project API key? More information: https://posthog.com/docs/api/overview]", }, ], sdkProcessingMetadata: { propagationContext: { traceId: 'ea26146e5a354cb0b3b1daebb3f90e33', spanId: '8d642089c3daa272' }, }, }) describe('PostHogSentryIntegration', () => { let posthog: PostHog let posthogSentry: PostHogSentryIntegration jest.useFakeTimers() beforeEach(() => { posthog = new PostHog('TEST_API_KEY', { host: 'http://example.com', fetchRetryCount: 0, }) posthogSentry = new PostHogSentryIntegration(posthog) mockedFetch.mockResolvedValue({ status: 200, text: () => Promise.resolve('ok'), json: () => Promise.resolve({ status: 'ok', }), } as any) }) afterEach(async () => { // ensure clean shutdown & no test interdependencies await posthog.shutdown() }) it('should forward sentry exceptions to posthog', async () => { expect(mockedFetch).toHaveBeenCalledTimes(0) const mockSentry = { getClient: () => ({ getDsn: () => ({ projectId: 123, }), }), } let processorFunction: any posthogSentry.setupOnce( (fn) => (processorFunction = fn), () => mockSentry ) processorFunction(createMockSentryException()) await waitForPromises() // First flush jest.runOnlyPendingTimers() // Flush timer await waitForPromises() // Second flush const batchEvents = getLastBatchEvents() expect(batchEvents).toEqual([ { distinct_id: 'EXAMPLE_APP_GLOBAL', event: '$exception', properties: { $exception_level: 'error', $exception_list: [ { mechanism: { handled: true, type: 'generic' }, stacktrace: { frames: [], type: 'raw' }, type: 'Error', value: 'example error', }, ], $exception_message: 'example error', $exception_type: 'Error', $exception_personURL: 'http://example.com/project/TEST_API_KEY/person/EXAMPLE_APP_GLOBAL', $sentry_event_id: '80a7023ac32c47f7acb0adaed600d149', $sentry_exception: { values: [ { type: 'Error', value: 'example error', stacktrace: { frames: [] }, mechanism: { type: 'generic', handled: true }, }, ], }, $sentry_exception_message: 'example error', $sentry_exception_type: 'Error', $sentry_tags: { posthog_distinct_id: 'EXAMPLE_APP_GLOBAL', 'PostHog Person URL': 'http://example.com/project/TEST_API_KEY/person/EXAMPLE_APP_GLOBAL', }, $lib: 'posthog-node', $lib_version: '1.2.3', $geoip_disable: true, }, type: 'capture', library: 'posthog-node', library_version: '1.2.3', timestamp: expect.any(String), uuid: expect.any(String), }, ]) }) })