/* eslint-disable no-console */
import * as React from 'react'
import { render } from '@testing-library/react'
import { __POSTHOG_ERROR_MESSAGES, PostHogErrorBoundary } from '../PostHogErrorBoundary'
import posthog from 'posthog-js'
import { setDefaultPostHogInstance } from '../../context/posthog-default'
describe('PostHogErrorBoundary component', () => {
beforeEach(() => {
setDefaultPostHogInstance(posthog)
})
afterEach(() => {
setDefaultPostHogInstance(undefined)
})
mockFunction(console, 'error')
mockFunction(console, 'warn')
mockFunction(posthog, 'captureException')
const renderWithError = (props: any) => render()
const renderWithoutError = (props?: any) => render()
it('should call captureException with error message', () => {
const { container } = renderWithError({ message: 'Test error', fallback:
})
expect(posthog.captureException).toHaveBeenCalledWith(new Error('Test error'), undefined)
expect(container.innerHTML).toBe('')
expect(console.error).toHaveBeenCalledTimes(1)
expect((console.error as any).mock.calls[0][1].message).toEqual('Test error')
})
it('should warn user when fallback is null', () => {
const { container } = renderWithError({ fallback: null })
expect(posthog.captureException).toHaveBeenCalledWith(new Error('Error'), undefined)
expect(container.innerHTML).toBe('')
expect(console.warn).toHaveBeenCalledWith(__POSTHOG_ERROR_MESSAGES.INVALID_FALLBACK)
})
it('should warn user when fallback is a string', () => {
const { container } = renderWithError({ fallback: 'hello' })
expect(posthog.captureException).toHaveBeenCalledWith(new Error('Error'), undefined)
expect(container.innerHTML).toBe('')
expect(console.warn).toHaveBeenCalledWith(__POSTHOG_ERROR_MESSAGES.INVALID_FALLBACK)
})
it('should add additional properties before sending event (as object)', () => {
const props = { team_id: '1234' }
renderWithError({ message: 'Kaboom', additionalProperties: props })
expect(posthog.captureException).toHaveBeenCalledWith(new Error('Kaboom'), props)
})
it('should add additional properties before sending event (as function)', () => {
const props = { team_id: '1234' }
renderWithError({
message: 'Kaboom',
additionalProperties: (err: Error) => {
expect(err.message).toBe('Kaboom')
return props
},
})
expect(posthog.captureException).toHaveBeenCalledWith(new Error('Kaboom'), props)
})
it('should render children without errors', () => {
const { container } = renderWithoutError()
expect(container.innerHTML).toBe('Amazing content
')
})
})
describe('captureException processing', () => {
beforeEach(() => {
setDefaultPostHogInstance(posthog)
})
afterEach(() => {
setDefaultPostHogInstance(undefined)
})
mockFunction(console, 'error')
mockFunction(console, 'warn')
mockFunction(posthog, 'capture')
const renderWithError = (props: any) => render()
it('should call capture with a stacktrace', () => {
renderWithError({ message: 'Kaboom', fallback: , additionalProperties: {} })
const captureCalls = (posthog.capture as jest.Mock).mock.calls
expect(captureCalls.length).toBe(1)
const exceptionList = captureCalls[0][1].$exception_list
expect(exceptionList.length).toBe(1)
const stacktrace = exceptionList[0].stacktrace
expect(stacktrace.frames.length).toBeGreaterThan(20)
})
})
function mockFunction(object: any, funcName: string) {
const originalFunc = object[funcName]
beforeEach(() => {
object[funcName] = jest.fn()
})
afterEach(() => {
object[funcName] = originalFunc
})
}
function ComponentWithError({ message }: { message: string }): React.ReactElement {
throw new Error(message)
}
function RenderWithError({ message = 'Error', fallback, additionalProperties }: any) {
return (
)
}
function RenderWithoutError({ additionalProperties }: any) {
return (
} additionalProperties={additionalProperties}>
Amazing content
)
}