All files / utils/error index.ts

95.76% Statements 113/118
76.47% Branches 13/17
100% Functions 5/5
95.76% Lines 113/118

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 1191x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 1x 1x 1x 1x 2x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 42x 42x 42x       42x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 14x 14x 14x 14x 14x 7x 7x 2x 2x 7x 7x 7x 4x 7x 4x 4x 7x 7x 7x 14x 14x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 14x 14x     14x 14x 14x 1x  
export {}
import Bugsnag from '@bugsnag/js'
import { Utils } from '../BaseUtils'
 
type ErrorHandlerProps = {
  error: unknown
  service?: string
  process?: string
  action?: string
  log?: boolean
  statusCode?: number
}
 
type BugsnagConfig = {
  apiKey: string
  appType?: string
  appVersion?: string
  context?: string
  releaseStage?: string
}
 
type ConstructorProps = {
  bugsnag?: BugsnagConfig | boolean
}
 
// Custom error class to allow for custom status codes
export class CustomError extends Error {
  constructor (message: string, statusCode?: number) {
    super(message)
    this.statusCode = statusCode || 500
  }
  statusCode: number
}
 
export class ServiceError extends CustomError {
  constructor(message: string, props: ErrorHandlerProps) {
    super(message, props.statusCode || 500)
    this.name = 'ServiceError'
    const $error = new ErrorUtils()
    $error.errorHandler(props)
  }
}
 
export class ControllerError extends CustomError {
  constructor(message: string, props: ErrorHandlerProps) {
    super(message, props.statusCode || 500)
    this.name = 'ControllerError'
    const $error = new ErrorUtils()
    $error.errorHandler(props)
  }
}
 
export class ErrorUtils extends Utils {
  useBugsnag: boolean
 
  constructor(props?: ConstructorProps) {
    super()
    this.useBugsnag = false
    if (props?.bugsnag) {
      this.useBugsnag = true
      Bugsnag.start(props.bugsnag as BugsnagConfig)
    }
  }
 
  /**
   * @description Error handler
   * @param {object} props
   * @param {object|string|number|boolean|unknown} props.error
   * @param {string} [props.service] - Identifies the source service.
   * @param {string} [props.process] - Identifies the source process.
   * @param {string} [props.action] - Identifies the source action.
   * @param {boolean} [props.log] - Specifies whether to include a console error log.
   * @param {boolean} [props.statusCode] - Sets the HTTP status code for the error or defaults to 500.
   * @param {boolean} [props.bugsnag] - Specifies whether to report error to BugSnag.
   * @returns {Error}
   */
  errorHandler = (props: ErrorHandlerProps): Error => {
    const { error, service, process, action, log, statusCode = 500} = props
 
    // Handle error value
    let $error = error
    if (!(error instanceof Error)) {
      let stringified = '[Unable to display the error value]'
      if (typeof error === 'string') {
        stringified = error
      }
      if (
        typeof error === 'number' ||
        typeof error === 'boolean' ||
        typeof error === 'object'
      ) {
        stringified = JSON.stringify(error)
      }
 
      $error = new Error(String(stringified))
    }
 
    if (log) {
      let message = ($error as Error).message
      if (action) {
        message = `[${action}] ${message}`
      }
      if (process) {
        message = `[${process}] ${message}`
      }
      if (service) {
        message = `[${service}] ${message}`
      }
      console.error(message)
    }
 
    if (this.useBugsnag) {
      Bugsnag.notify($error as Error);
    }
 
    return $error as Error
  }
}