Updates the plugin to 3.0
Test:
```sh
NEXT_PUBLIC_SENTRY_DSN=<DSN here> pnpm dev plugin-sentry
```
Example:
```ts
sentryPlugin({
options: {
captureErrors: [400, 403],
context: ({ defaultContext, req }) => {
return {
...defaultContext,
tags: {
locale: req.locale,
},
}
},
debug: true,
},
Sentry,
})
```
102 lines
2.5 KiB
TypeScript
102 lines
2.5 KiB
TypeScript
import type { AfterErrorHook, AfterErrorHookArgs, Config, PayloadRequest } from 'payload'
|
|
|
|
import { APIError, defaults } from 'payload'
|
|
|
|
import { sentryPlugin } from './index'
|
|
import { randomUUID } from 'crypto'
|
|
|
|
const mockExceptionID = randomUUID()
|
|
|
|
const mockSentry = {
|
|
captureException() {
|
|
return mockExceptionID
|
|
},
|
|
}
|
|
|
|
describe('@payloadcms/plugin-sentry - unit', () => {
|
|
it('should run the plugin', () => {
|
|
const plugin = sentryPlugin({ Sentry: mockSentry, enabled: true })
|
|
const config = plugin(createConfig())
|
|
|
|
assertPluginRan(config)
|
|
})
|
|
|
|
it('should default enabled: true', () => {
|
|
const plugin = sentryPlugin({ Sentry: mockSentry })
|
|
const config = plugin(createConfig())
|
|
|
|
assertPluginRan(config)
|
|
})
|
|
|
|
it('should not run if Sentry is not provided', () => {
|
|
const plugin = sentryPlugin({ enabled: true })
|
|
const config = plugin(createConfig())
|
|
|
|
assertPluginDidNotRun(config)
|
|
})
|
|
|
|
it('should respect enabled: false', () => {
|
|
const plugin = sentryPlugin({ Sentry: mockSentry, enabled: false })
|
|
const config = plugin(createConfig())
|
|
|
|
assertPluginDidNotRun(config)
|
|
})
|
|
|
|
it('should execute Sentry.captureException with correct errors / args', async () => {
|
|
const hintTimestamp = Date.now()
|
|
|
|
const plugin = sentryPlugin({
|
|
Sentry: mockSentry,
|
|
options: {
|
|
context: ({ defaultContext }) => ({
|
|
...defaultContext,
|
|
extra: {
|
|
...defaultContext.extra,
|
|
hintTimestamp,
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
const config = plugin(createConfig())
|
|
|
|
const hook = config.hooks?.afterError?.[0] as AfterErrorHook
|
|
|
|
const error = new APIError('ApiError', 500)
|
|
|
|
const afterErrorHookArgs: AfterErrorHookArgs = {
|
|
req: {} as PayloadRequest,
|
|
context: {},
|
|
error,
|
|
collection: { slug: 'mock-slug' } as any,
|
|
}
|
|
|
|
const captureExceptionSpy = jest.spyOn(mockSentry, 'captureException')
|
|
|
|
await hook(afterErrorHookArgs)
|
|
|
|
expect(captureExceptionSpy).toHaveBeenCalledTimes(1)
|
|
expect(captureExceptionSpy).toHaveBeenCalledWith(error, {
|
|
extra: {
|
|
errorCollectionSlug: 'mock-slug',
|
|
hintTimestamp,
|
|
},
|
|
})
|
|
expect(captureExceptionSpy).toHaveReturnedWith(mockExceptionID)
|
|
})
|
|
})
|
|
|
|
function assertPluginRan(config: Config) {
|
|
expect(config.hooks?.afterError?.[0]).toBeDefined()
|
|
}
|
|
|
|
function assertPluginDidNotRun(config: Config) {
|
|
expect(config.hooks?.afterError?.[0]).toBeUndefined()
|
|
}
|
|
|
|
function createConfig(overrides?: Partial<Config>): Config {
|
|
return {
|
|
...defaults,
|
|
...overrides,
|
|
} as Config
|
|
}
|