| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- import * as Sentry from '@sentry/nextjs'
- import { beforeEach, describe, expect, it, vi } from 'vitest'
- import { captureCriticalError } from './error-reporting'
- import { ResponseError } from '@/types'
- vi.mock('@sentry/nextjs', () => ({
- captureException: vi.fn(),
- withScope: vi.fn((cb: (scope: any) => void) => {
- const scope = { setTag: vi.fn() }
- cb(scope)
- }),
- }))
- describe('error-reporting', () => {
- beforeEach(() => {
- vi.clearAllMocks()
- })
- describe('captureCriticalError', () => {
- it('should not capture error if message is empty', () => {
- const error = { message: '' }
- captureCriticalError(error, 'test context')
- expect(Sentry.captureException).not.toHaveBeenCalled()
- })
- it('should capture regular Error objects', () => {
- const error = new Error('Something went wrong')
- captureCriticalError(error, 'test action')
- expect(Sentry.captureException).toHaveBeenCalledWith(
- expect.objectContaining({ message: 'Something went wrong', name: 'CriticalError' })
- )
- })
- it('should not capture whitelisted error messages', () => {
- const error = new Error('email must be an email')
- captureCriticalError(error, 'validation')
- expect(Sentry.captureException).not.toHaveBeenCalled()
- })
- it('should not capture errors with partial whitelisted message', () => {
- const error = new Error('User error: A user with this email already exists in the system')
- captureCriticalError(error, 'sign up')
- expect(Sentry.captureException).not.toHaveBeenCalled()
- })
- it('should capture errors that are not whitelisted', () => {
- const error = new Error('Database connection failed')
- captureCriticalError(error, 'database')
- expect(Sentry.captureException).toHaveBeenCalledWith(
- expect.objectContaining({ message: 'Database connection failed', name: 'CriticalError' })
- )
- })
- it('should capture 5XX ResponseError', () => {
- const error = new ResponseError(
- 'Internal server error',
- 500,
- undefined,
- undefined,
- '/api/test'
- )
- captureCriticalError(error, 'api call')
- expect(Sentry.captureException).toHaveBeenCalledWith(
- expect.objectContaining({
- message: 'requestPathname /api/test w/ message: Internal server error',
- name: 'CriticalError',
- })
- )
- })
- it('should not capture 4XX ResponseError', () => {
- const error = new ResponseError('Not found', 404, undefined, undefined, '/api/test')
- captureCriticalError(error, 'api call')
- expect(Sentry.captureException).not.toHaveBeenCalled()
- })
- it('should capture ResponseError with 5XX status code', () => {
- const error = new ResponseError('Gateway timeout', 504, undefined, undefined, '/api/gateway')
- captureCriticalError(error, 'gateway request')
- expect(Sentry.captureException).toHaveBeenCalledWith(
- expect.objectContaining({
- message: 'requestPathname /api/gateway w/ message: Gateway timeout',
- name: 'CriticalError',
- })
- )
- })
- it('should capture ResponseError without code or requestPathname', () => {
- const error = new ResponseError('Unknown error')
- captureCriticalError(error, 'unknown')
- expect(Sentry.captureException).toHaveBeenCalledWith(
- expect.objectContaining({
- message: 'Response Error (no code or requestPathname) w/ message: Unknown error',
- name: 'CriticalError',
- })
- )
- })
- it('should capture unknown error objects with message property', () => {
- const error = { message: 'Custom error object' }
- captureCriticalError(error, 'custom')
- expect(Sentry.captureException).toHaveBeenCalledWith(
- expect.objectContaining({ message: 'Custom error object', name: 'CriticalError' })
- )
- })
- it('should not capture unknown error without message', () => {
- const error = { foo: 'bar' }
- captureCriticalError(error as any, 'no message')
- expect(Sentry.captureException).not.toHaveBeenCalled()
- })
- it('should not capture whitelisted password validation error', () => {
- const error = new Error(
- 'Password is known to be weak and easy to guess, please choose a different one'
- )
- captureCriticalError(error, 'password update')
- expect(Sentry.captureException).not.toHaveBeenCalled()
- })
- it('should not capture whitelisted TOTP error', () => {
- const error = new Error('Invalid TOTP code entered')
- captureCriticalError(error, 'mfa verification')
- expect(Sentry.captureException).not.toHaveBeenCalled()
- })
- it('should not capture whitelisted project name error', () => {
- const error = new Error('name should not contain a . string')
- captureCriticalError(error, 'create project')
- expect(Sentry.captureException).not.toHaveBeenCalled()
- })
- it('should capture non-whitelisted errors even if similar to whitelisted ones', () => {
- const error = new Error('email format is invalid')
- captureCriticalError(error, 'validation')
- expect(Sentry.captureException).toHaveBeenCalledWith(
- expect.objectContaining({ message: 'email format is invalid', name: 'CriticalError' })
- )
- })
- it('should handle Error objects with empty message', () => {
- const error = new Error('')
- captureCriticalError(error, 'empty error')
- expect(Sentry.captureException).not.toHaveBeenCalled()
- })
- it('should handle ResponseError at boundary of 4XX/5XX (499)', () => {
- const error = new ResponseError(
- 'Client closed request',
- 499,
- undefined,
- undefined,
- '/api/test'
- )
- captureCriticalError(error, 'request')
- expect(Sentry.captureException).not.toHaveBeenCalled()
- })
- it('should handle ResponseError at boundary of 4XX/5XX (500)', () => {
- const error = new ResponseError('Internal error', 500, undefined, undefined, '/api/test')
- captureCriticalError(error, 'request')
- expect(Sentry.captureException).toHaveBeenCalledWith(
- expect.objectContaining({
- message: 'requestPathname /api/test w/ message: Internal error',
- name: 'CriticalError',
- })
- )
- })
- })
- })
|