o-error.test.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. const OError = require('..')
  2. const { expectError } = require('./support')
  3. class CustomError1 extends OError {
  4. constructor(options) {
  5. super({ message: 'failed to foo', ...options })
  6. }
  7. }
  8. class CustomError2 extends OError {
  9. constructor(options) {
  10. super({ message: 'failed to bar', ...options })
  11. }
  12. }
  13. describe('OError', function () {
  14. it('handles a custom error type with a cause', function () {
  15. function doSomethingBadInternally() {
  16. throw new Error('internal error')
  17. }
  18. function doSomethingBad() {
  19. try {
  20. doSomethingBadInternally()
  21. } catch (err) {
  22. throw new CustomError1({ info: { userId: 123 } }).withCause(err)
  23. }
  24. }
  25. try {
  26. doSomethingBad()
  27. expect.fail('should have thrown')
  28. } catch (e) {
  29. expectError(e, {
  30. name: 'CustomError1',
  31. klass: CustomError1,
  32. message: 'CustomError1: failed to foo: internal error',
  33. firstFrameRx: /doSomethingBad/,
  34. })
  35. expect(OError.getFullInfo(e)).to.deep.equal({ userId: 123 })
  36. const fullStack = OError.getFullStack(e)
  37. expect(fullStack).to.match(
  38. /^CustomError1: failed to foo: internal error$/m
  39. )
  40. expect(fullStack).to.match(/^caused by: Error: internal error$/m)
  41. }
  42. })
  43. it('handles a custom error type with nested causes', function () {
  44. function doSomethingBadInternally() {
  45. throw new Error('internal error')
  46. }
  47. function doBar() {
  48. try {
  49. doSomethingBadInternally()
  50. } catch (err) {
  51. throw new CustomError2({ info: { database: 'a' } }).withCause(err)
  52. }
  53. }
  54. function doFoo() {
  55. try {
  56. doBar()
  57. } catch (err) {
  58. throw new CustomError1({ info: { userId: 123 } }).withCause(err)
  59. }
  60. }
  61. try {
  62. doFoo()
  63. expect.fail('should have thrown')
  64. } catch (e) {
  65. expectError(e, {
  66. name: 'CustomError1',
  67. klass: CustomError1,
  68. message: 'CustomError1: failed to foo: failed to bar: internal error',
  69. firstFrameRx: /doFoo/,
  70. })
  71. expect(OError.getFullInfo(e)).to.deep.equal({
  72. userId: 123,
  73. database: 'a',
  74. })
  75. const fullStack = OError.getFullStack(e)
  76. expect(fullStack).to.match(
  77. /^CustomError1: failed to foo: failed to bar: internal error$/m
  78. )
  79. expect(fullStack).to.match(
  80. /^caused by: CustomError2: failed to bar: internal error$/m
  81. )
  82. expect(fullStack).to.match(/^caused by: Error: internal error$/m)
  83. }
  84. })
  85. it('handles a custom error without info', function () {
  86. try {
  87. throw new CustomError1({})
  88. } catch (e) {
  89. expect(OError.getFullInfo(e)).to.deep.equal({})
  90. const infoKey = Object.keys(e).find((k) => k === 'info')
  91. expect(infoKey).to.not.exist
  92. }
  93. })
  94. })