mirror of
https://github.com/hanzoai/insights-js.git
synced 2026-10-30 18:34:19 +00:00
Bulk rename across 989 files: - Package names: posthog-js → @hanzo/insights, posthog-node → @hanzo/insights-node, etc. - Repository URLs: posthog/posthog-js → hanzoai/insights-js - Brand names: PostHog → Insights - File renames: 259 reference JSON files, source files, workflow files - Directory rename: eslint-plugin-posthog-js → eslint-plugin-insights Remaining: 8 refs to @posthog/rrweb-* (real npm deps, need fork+publish)
222 lines
8.9 KiB
TypeScript
222 lines
8.9 KiB
TypeScript
import { expect } from '../utils/insights-playwright-test-base'
|
|
import { EventsPage, test } from '../../fixtures'
|
|
import { BasePage } from 'fixtures/page'
|
|
|
|
test.describe('ErrorTracking autocapture', () => {
|
|
async function checkException(events: EventsPage, browserName: string) {
|
|
const exception = await events.waitForEvent('$exception')
|
|
expect(exception.properties.$exception_list[0].stacktrace.type).toEqual('raw')
|
|
expect(exception.properties.$exception_list[0].stacktrace.frames.length).toEqual(1)
|
|
expect(exception.properties.$exception_list[0].stacktrace.frames[0].function).toEqual(
|
|
// turns out firefox and chromium capture different info :/
|
|
browserName === 'chromium' ? 'HTMLButtonElement.onclick' : 'onclick'
|
|
)
|
|
}
|
|
|
|
async function checkNoException(page: BasePage, events: EventsPage) {
|
|
await page.close()
|
|
const exceptionCount = events.countByName('$exception')
|
|
expect(exceptionCount).toEqual(0)
|
|
}
|
|
|
|
test.use({ url: '/playground/cypress/index.html' })
|
|
|
|
test.describe('autocapture', () => {
|
|
test('should capture thrown errors when remote config is enabled', async ({
|
|
insights,
|
|
page,
|
|
network,
|
|
events,
|
|
browserName,
|
|
}) => {
|
|
await network.mockFlags({
|
|
autocaptureExceptions: true,
|
|
})
|
|
await insights.init()
|
|
await network.waitForFlags()
|
|
await page.click('[data-cy-button-throws-error]')
|
|
await checkException(events, browserName)
|
|
})
|
|
|
|
test('should capture thrown errors when local config is enabled', async ({
|
|
insights,
|
|
page,
|
|
network,
|
|
events,
|
|
browserName,
|
|
}) => {
|
|
await insights.init({
|
|
capture_exceptions: true,
|
|
})
|
|
await network.waitForFlags()
|
|
await page.click('[data-cy-button-throws-error]')
|
|
await checkException(events, browserName)
|
|
})
|
|
|
|
test('should not capture when remote disabled', async ({ insights, page, network, events }) => {
|
|
await network.mockFlags({
|
|
autocaptureExceptions: false,
|
|
})
|
|
await insights.init()
|
|
await network.waitForFlags()
|
|
await page.click('[data-cy-button-throws-error]')
|
|
await checkNoException(page, events)
|
|
})
|
|
|
|
test('should not capture when config disabled', async ({ insights, page, network, events }) => {
|
|
await insights.init({
|
|
capture_exceptions: false,
|
|
})
|
|
await network.waitForFlags()
|
|
await page.click('[data-cy-button-throws-error]')
|
|
await checkNoException(page, events)
|
|
})
|
|
|
|
test('should not capture unhandled promise rejection when config disabled', async ({
|
|
insights,
|
|
page,
|
|
network,
|
|
events,
|
|
}) => {
|
|
await insights.init({
|
|
capture_exceptions: false,
|
|
})
|
|
await network.waitForFlags()
|
|
await page.evaluate(() => {
|
|
Promise.reject(new Error('An unknown error occured'))
|
|
})
|
|
await checkNoException(page, events)
|
|
})
|
|
})
|
|
|
|
test.describe('unhandled promise rejections', () => {
|
|
test('should capture with error', async ({ insights, page, network, events, browserName }) => {
|
|
await insights.init({
|
|
capture_exceptions: true,
|
|
})
|
|
await network.waitForFlags()
|
|
await page.evaluate(() => {
|
|
class CustomError extends Error {
|
|
constructor(message: string) {
|
|
super(message)
|
|
this.name = 'CustomError'
|
|
}
|
|
}
|
|
Promise.reject(new CustomError('An unknown error occured'))
|
|
})
|
|
const event = await events.waitForEvent('$exception')
|
|
const first_exception = event.properties.$exception_list[0]
|
|
expect(first_exception.type).toBe('CustomError')
|
|
expect(first_exception.value).toBe('An unknown error occured')
|
|
expect(first_exception.mechanism.handled).toBe(false)
|
|
const frames = first_exception.stacktrace.frames
|
|
if (browserName === 'chromium') {
|
|
expect(frames).toHaveLength(3)
|
|
} else {
|
|
expect(frames).toHaveLength(0)
|
|
}
|
|
})
|
|
|
|
test('should capture with string', async ({ insights, page, network, events }) => {
|
|
await insights.init({
|
|
capture_exceptions: true,
|
|
})
|
|
await network.waitForFlags()
|
|
await page.evaluate(() => {
|
|
Promise.reject('An unknown error occured')
|
|
})
|
|
const exception = await events.waitForEvent('$exception')
|
|
expect(exception).toBeDefined()
|
|
expect(exception.properties.$exception_list[0].type).toBe('UnhandledRejection')
|
|
expect(exception.properties.$exception_list[0].value).toBe(
|
|
'Non-Error promise rejection captured with value: An unknown error occured'
|
|
)
|
|
const stacktrace = exception.properties.$exception_list[0].stacktrace
|
|
expect(stacktrace).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
test.describe('unhandled errors', () => {
|
|
test('should capture ReferenceError', async ({ insights, network, page, events, browserName }) => {
|
|
await insights.init({
|
|
capture_exceptions: true,
|
|
})
|
|
await network.waitForFlags()
|
|
await page.addScriptTag({
|
|
content: 'gibberish',
|
|
type: 'module',
|
|
})
|
|
const event = await events.waitForEvent('$exception')
|
|
const first_exception = event.properties.$exception_list[0]
|
|
expect(first_exception.type).toBe('ReferenceError')
|
|
switch (browserName) {
|
|
case 'webkit':
|
|
expect(first_exception.value).toBe("Can't find variable: gibberish")
|
|
break
|
|
case 'chromium':
|
|
case 'firefox':
|
|
expect(first_exception.value).toBe('gibberish is not defined')
|
|
break
|
|
}
|
|
|
|
expect(first_exception.mechanism.handled).toBe(false)
|
|
const frames = first_exception.stacktrace.frames
|
|
expect(frames).toHaveLength(1)
|
|
})
|
|
|
|
test('should capture SyntaxError', async ({ insights, network, page, events, browserName }) => {
|
|
await insights.init({
|
|
capture_exceptions: true,
|
|
})
|
|
await network.waitForFlags()
|
|
await page.addScriptTag({
|
|
content: "let toto = 'asdsds; ",
|
|
type: 'module',
|
|
})
|
|
const event = await events.waitForEvent('$exception')
|
|
const first_exception = event.properties.$exception_list[0]
|
|
expect(first_exception.type).toBe('SyntaxError')
|
|
expect(first_exception.mechanism.handled).toBe(false)
|
|
const frames = first_exception.stacktrace?.frames || []
|
|
switch (browserName) {
|
|
case 'chromium':
|
|
expect(first_exception.value).toBe(
|
|
"Failed to execute 'appendChild' on 'Node': Invalid or unexpected token"
|
|
)
|
|
expect(frames).toHaveLength(3)
|
|
break
|
|
case 'firefox':
|
|
expect(first_exception.value).toBe("'' literal not terminated before end of script")
|
|
expect(frames).toHaveLength(5)
|
|
break
|
|
case 'webkit':
|
|
expect(first_exception.value).toBe('Unexpected EOF')
|
|
expect(frames).toHaveLength(0)
|
|
break
|
|
}
|
|
})
|
|
|
|
test('should capture console errors', async ({ insights, network, page, events }) => {
|
|
await insights.init({
|
|
capture_exceptions: {
|
|
capture_console_errors: true,
|
|
capture_unhandled_errors: false,
|
|
capture_unhandled_rejections: false,
|
|
},
|
|
})
|
|
await network.waitForFlags()
|
|
await page.evaluate(() => {
|
|
//eslint-disable-next-line no-console
|
|
console.error('This error should be captured with a stack')
|
|
})
|
|
|
|
const event = await events.waitForEvent('$exception')
|
|
const first_exception = event.properties.$exception_list[0]
|
|
expect(first_exception.type).toBe('Error')
|
|
expect(first_exception.value).toBe('This error should be captured with a stack')
|
|
expect(first_exception.stacktrace).toBeDefined()
|
|
expect(first_exception.mechanism.handled).toBe(false)
|
|
})
|
|
})
|
|
})
|