fastify 3.27.3 → 4.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/.taprc +3 -0
  2. package/README.md +7 -7
  3. package/build/build-error-serializer.js +27 -0
  4. package/build/build-validation.js +47 -35
  5. package/docs/Guides/Database.md +320 -0
  6. package/docs/Guides/Getting-Started.md +7 -7
  7. package/docs/Guides/Plugins-Guide.md +1 -1
  8. package/docs/Guides/Serverless.md +3 -3
  9. package/docs/Guides/Testing.md +2 -2
  10. package/docs/Migration-Guide-V4.md +12 -0
  11. package/docs/Reference/ContentTypeParser.md +4 -0
  12. package/docs/Reference/Decorators.md +2 -2
  13. package/docs/Reference/Encapsulation.md +2 -2
  14. package/docs/Reference/Errors.md +51 -6
  15. package/docs/Reference/HTTP2.md +3 -3
  16. package/docs/Reference/Hooks.md +4 -7
  17. package/docs/Reference/LTS.md +5 -4
  18. package/docs/Reference/Plugins.md +3 -3
  19. package/docs/Reference/Reply.md +23 -22
  20. package/docs/Reference/Request.md +1 -3
  21. package/docs/Reference/Routes.md +22 -15
  22. package/docs/Reference/Server.md +69 -119
  23. package/docs/Reference/TypeScript.md +20 -22
  24. package/docs/Reference/Validation-and-Serialization.md +30 -55
  25. package/docs/Type-Providers.md +257 -0
  26. package/examples/asyncawait.js +1 -1
  27. package/examples/benchmark/hooks-benchmark-async-await.js +1 -1
  28. package/examples/benchmark/hooks-benchmark.js +1 -1
  29. package/examples/benchmark/simple.js +1 -1
  30. package/examples/hooks.js +2 -2
  31. package/examples/http2.js +1 -1
  32. package/examples/https.js +1 -1
  33. package/examples/parser.js +1 -1
  34. package/examples/route-prefix.js +1 -1
  35. package/examples/shared-schema.js +1 -1
  36. package/examples/simple-stream.js +18 -0
  37. package/examples/simple.js +1 -1
  38. package/examples/simple.mjs +1 -1
  39. package/examples/typescript-server.ts +1 -1
  40. package/examples/use-plugin.js +1 -1
  41. package/fastify.d.ts +34 -22
  42. package/fastify.js +40 -36
  43. package/lib/configValidator.js +902 -1023
  44. package/lib/contentTypeParser.js +6 -16
  45. package/lib/context.js +36 -10
  46. package/lib/decorate.js +3 -1
  47. package/lib/error-handler.js +158 -0
  48. package/lib/error-serializer.js +257 -0
  49. package/lib/errors.js +43 -9
  50. package/lib/fourOhFour.js +31 -20
  51. package/lib/handleRequest.js +10 -13
  52. package/lib/hooks.js +14 -9
  53. package/lib/pluginOverride.js +0 -3
  54. package/lib/pluginUtils.js +3 -2
  55. package/lib/reply.js +29 -158
  56. package/lib/request.js +13 -10
  57. package/lib/route.js +131 -138
  58. package/lib/schema-controller.js +2 -2
  59. package/lib/schemas.js +27 -1
  60. package/lib/server.js +241 -116
  61. package/lib/symbols.js +4 -3
  62. package/lib/validation.js +2 -1
  63. package/lib/warnings.js +4 -12
  64. package/lib/wrapThenable.js +4 -11
  65. package/package.json +37 -39
  66. package/test/404s.test.js +258 -125
  67. package/test/500s.test.js +3 -3
  68. package/test/als.test.js +1 -1
  69. package/test/async-await.test.js +20 -76
  70. package/test/bodyLimit.test.js +1 -1
  71. package/test/build-certificate.js +6 -7
  72. package/test/case-insensitive.test.js +4 -4
  73. package/test/close-pipelining.test.js +2 -2
  74. package/test/close.test.js +11 -11
  75. package/test/content-parser.test.js +32 -0
  76. package/test/context-config.test.js +52 -0
  77. package/test/custom-http-server.test.js +14 -7
  78. package/test/custom-parser-async.test.js +1 -66
  79. package/test/custom-parser.test.js +92 -159
  80. package/test/custom-querystring-parser.test.js +3 -3
  81. package/test/decorator.test.js +11 -13
  82. package/test/delete.test.js +6 -6
  83. package/test/encapsulated-error-handler.test.js +50 -0
  84. package/test/esm/index.test.js +0 -14
  85. package/test/fastify-instance.test.js +4 -4
  86. package/test/fluent-schema.test.js +4 -4
  87. package/test/genReqId.test.js +1 -1
  88. package/test/get.test.js +4 -4
  89. package/test/handler-context.test.js +2 -2
  90. package/test/head.test.js +1 -1
  91. package/test/helper.js +19 -4
  92. package/test/hooks-async.test.js +15 -48
  93. package/test/hooks.on-ready.test.js +10 -5
  94. package/test/hooks.test.js +78 -119
  95. package/test/http2/closing.test.js +10 -16
  96. package/test/http2/constraint.test.js +1 -1
  97. package/test/http2/head.test.js +1 -1
  98. package/test/http2/plain.test.js +1 -1
  99. package/test/http2/secure-with-fallback.test.js +1 -1
  100. package/test/http2/secure.test.js +1 -1
  101. package/test/http2/unknown-http-method.test.js +4 -10
  102. package/test/https/custom-https-server.test.js +12 -6
  103. package/test/https/https.test.js +1 -1
  104. package/test/input-validation.js +3 -3
  105. package/test/internals/handleRequest.test.js +6 -43
  106. package/test/internals/initialConfig.test.js +41 -12
  107. package/test/internals/logger.test.js +2 -2
  108. package/test/internals/reply.test.js +281 -40
  109. package/test/internals/request.test.js +13 -7
  110. package/test/internals/server.test.js +88 -0
  111. package/test/listen.deprecated.test.js +202 -0
  112. package/test/listen.test.js +118 -150
  113. package/test/logger.test.js +82 -42
  114. package/test/maxRequestsPerSocket.test.js +8 -6
  115. package/test/middleware.test.js +2 -25
  116. package/test/nullable-validation.test.js +53 -16
  117. package/test/output-validation.test.js +1 -1
  118. package/test/plugin.test.js +47 -21
  119. package/test/pretty-print.test.js +22 -10
  120. package/test/promises.test.js +1 -1
  121. package/test/proto-poisoning.test.js +6 -6
  122. package/test/register.test.js +3 -3
  123. package/test/reply-error.test.js +126 -15
  124. package/test/request-error.test.js +3 -6
  125. package/test/route-hooks.test.js +18 -18
  126. package/test/route-prefix.test.js +2 -1
  127. package/test/route.test.js +206 -22
  128. package/test/router-options.test.js +2 -2
  129. package/test/schema-examples.test.js +11 -5
  130. package/test/schema-feature.test.js +25 -20
  131. package/test/schema-serialization.test.js +9 -9
  132. package/test/schema-special-usage.test.js +5 -153
  133. package/test/schema-validation.test.js +9 -9
  134. package/test/skip-reply-send.test.js +2 -2
  135. package/test/stream.test.js +82 -23
  136. package/test/throw.test.js +8 -5
  137. package/test/trust-proxy.test.js +6 -6
  138. package/test/type-provider.test.js +20 -0
  139. package/test/types/fastify.test-d.ts +10 -18
  140. package/test/types/import.js +2 -0
  141. package/test/types/import.ts +1 -0
  142. package/test/types/instance.test-d.ts +68 -17
  143. package/test/types/logger.test-d.ts +44 -15
  144. package/test/types/reply.test-d.ts +2 -1
  145. package/test/types/route.test-d.ts +8 -2
  146. package/test/types/schema.test-d.ts +2 -39
  147. package/test/types/type-provider.test-d.ts +417 -0
  148. package/test/url-rewriting.test.js +3 -3
  149. package/test/validation-error-handling.test.js +8 -8
  150. package/test/versioned-routes.test.js +30 -18
  151. package/test/wrapThenable.test.js +7 -6
  152. package/types/content-type-parser.d.ts +17 -8
  153. package/types/hooks.d.ts +102 -59
  154. package/types/instance.d.ts +244 -118
  155. package/types/logger.d.ts +18 -104
  156. package/types/plugin.d.ts +10 -4
  157. package/types/reply.d.ts +18 -12
  158. package/types/request.d.ts +10 -5
  159. package/types/route.d.ts +42 -31
  160. package/types/schema.d.ts +1 -1
  161. package/types/type-provider.d.ts +99 -0
  162. package/types/utils.d.ts +1 -1
  163. package/lib/schema-compilers.js +0 -12
  164. package/test/emit-warning.test.js +0 -166
@@ -89,7 +89,7 @@ test('fastify.register with fastify-plugin should not encapsulate his code', t =
89
89
  t.notOk(fastify.test)
90
90
  })
91
91
 
92
- fastify.listen(0, err => {
92
+ fastify.listen({ port: 0 }, err => {
93
93
  t.error(err)
94
94
  fastify.server.unref()
95
95
 
@@ -168,7 +168,7 @@ test('fastify.register with fastify-plugin should provide access to external fas
168
168
  t.notOk(fastify.global)
169
169
  })
170
170
 
171
- fastify.listen(0, err => {
171
+ fastify.listen({ port: 0 }, err => {
172
172
  t.error(err)
173
173
  fastify.server.unref()
174
174
 
@@ -223,7 +223,7 @@ test('fastify.register with fastify-plugin registers root level plugins', t => {
223
223
  reply.send({ test: fastify.test })
224
224
  })
225
225
 
226
- fastify.listen(0, err => {
226
+ fastify.listen({ port: 0 }, err => {
227
227
  t.error(err)
228
228
  fastify.server.unref()
229
229
 
@@ -285,7 +285,7 @@ test('check dependencies - should not throw', t => {
285
285
  t.notOk(fastify.otherTest)
286
286
  })
287
287
 
288
- fastify.listen(0, err => {
288
+ fastify.listen({ port: 0 }, err => {
289
289
  t.error(err)
290
290
  fastify.server.unref()
291
291
 
@@ -337,7 +337,7 @@ test('check dependencies - should throw', t => {
337
337
  t.notOk(fastify.test)
338
338
  })
339
339
 
340
- fastify.listen(0, err => {
340
+ fastify.listen({ port: 0 }, err => {
341
341
  t.error(err)
342
342
  fastify.server.unref()
343
343
 
@@ -375,7 +375,7 @@ test('set the plugin name based on the plugin displayName symbol', t => {
375
375
  done()
376
376
  }, { name: 'plugin-B' }))
377
377
 
378
- fastify.listen(0, err => {
378
+ fastify.listen({ port: 0 }, err => {
379
379
  t.error(err)
380
380
  fastify.close()
381
381
  })
@@ -405,7 +405,7 @@ test('plugin name will change when using no encapsulation', t => {
405
405
  done()
406
406
  }, { name: 'plugin-A' }))
407
407
 
408
- fastify.listen(0, err => {
408
+ fastify.listen({ port: 0 }, err => {
409
409
  t.error(err)
410
410
  fastify.close()
411
411
  })
@@ -417,7 +417,7 @@ test('plugin name is undefined when accessing in no plugin context', t => {
417
417
 
418
418
  t.equal(fastify.pluginName, undefined)
419
419
 
420
- fastify.listen(0, err => {
420
+ fastify.listen({ port: 0 }, err => {
421
421
  t.error(err)
422
422
  fastify.close()
423
423
  })
@@ -445,7 +445,7 @@ test('set the plugin name based on the plugin function name', t => {
445
445
  done()
446
446
  })
447
447
 
448
- fastify.listen(0, err => {
448
+ fastify.listen({ port: 0 }, err => {
449
449
  t.error(err)
450
450
  fastify.close()
451
451
  })
@@ -472,7 +472,7 @@ test('approximate a plugin name when no meta data is available', t => {
472
472
  done()
473
473
  })
474
474
 
475
- fastify.listen(0, err => {
475
+ fastify.listen({ port: 0 }, err => {
476
476
  t.error(err)
477
477
  fastify.close()
478
478
  })
@@ -495,7 +495,7 @@ test('approximate a plugin name also when fastify-plugin has no meta data', t =>
495
495
  done()
496
496
  }))
497
497
 
498
- fastify.listen(0, err => {
498
+ fastify.listen({ port: 0 }, err => {
499
499
  t.error(err)
500
500
  fastify.close()
501
501
  })
@@ -535,7 +535,7 @@ test('plugin encapsulation', t => {
535
535
  t.notOk(fastify.test)
536
536
  })
537
537
 
538
- fastify.listen(0, err => {
538
+ fastify.listen({ port: 0 }, err => {
539
539
  t.error(err)
540
540
  fastify.server.unref()
541
541
 
@@ -569,7 +569,7 @@ test('if a plugin raises an error and there is not a callback to handle it, the
569
569
  done(new Error('err'))
570
570
  })
571
571
 
572
- fastify.listen(0, err => {
572
+ fastify.listen({ port: 0 }, err => {
573
573
  t.ok(err instanceof Error)
574
574
  t.equal(err.message, 'err')
575
575
  })
@@ -612,7 +612,7 @@ test('add hooks after route declaration', t => {
612
612
  done()
613
613
  })
614
614
 
615
- fastify.listen(0, err => {
615
+ fastify.listen({ port: 0 }, err => {
616
616
  t.error(err)
617
617
 
618
618
  sget({
@@ -651,7 +651,7 @@ test('nested plugins', t => {
651
651
  done()
652
652
  }, { prefix: '/parent' })
653
653
 
654
- fastify.listen(0, err => {
654
+ fastify.listen({ port: 0 }, err => {
655
655
  t.error(err)
656
656
 
657
657
  sget({
@@ -693,7 +693,7 @@ test('nested plugins awaited', t => {
693
693
  }, { prefix: '/child2' })
694
694
  }, { prefix: '/parent' })
695
695
 
696
- fastify.listen(0, err => {
696
+ fastify.listen({ port: 0 }, err => {
697
697
  t.error(err)
698
698
 
699
699
  sget({
@@ -864,7 +864,7 @@ test('plugin metadata - dependencies (nested)', t => {
864
864
  })
865
865
 
866
866
  test('pluginTimeout', t => {
867
- t.plan(2)
867
+ t.plan(5)
868
868
  const fastify = Fastify({
869
869
  pluginTimeout: 10
870
870
  })
@@ -873,13 +873,35 @@ test('pluginTimeout', t => {
873
873
  })
874
874
  fastify.ready((err) => {
875
875
  t.ok(err)
876
- t.equal(err.code, 'ERR_AVVIO_PLUGIN_TIMEOUT')
876
+ t.equal(err.message,
877
+ "fastify-plugin: Plugin did not start in time: 'function (app, opts, done) { -- // to no call done on purpose'. You may have forgotten to call 'done' function or to resolve a Promise")
878
+ t.equal(err.code, 'FST_ERR_PLUGIN_TIMEOUT')
879
+ t.ok(err.cause)
880
+ t.equal(err.cause.code, 'AVV_ERR_READY_TIMEOUT')
881
+ })
882
+ })
883
+
884
+ test('pluginTimeout - named function', { only: true }, t => {
885
+ t.plan(5)
886
+ const fastify = Fastify({
887
+ pluginTimeout: 10
888
+ })
889
+ fastify.register(function nameFunction (app, opts, done) {
890
+ // to no call done on purpose
891
+ })
892
+ fastify.ready((err) => {
893
+ t.ok(err)
894
+ t.equal(err.message,
895
+ "fastify-plugin: Plugin did not start in time: 'nameFunction'. You may have forgotten to call 'done' function or to resolve a Promise")
896
+ t.equal(err.code, 'FST_ERR_PLUGIN_TIMEOUT')
897
+ t.ok(err.cause)
898
+ t.equal(err.cause.code, 'AVV_ERR_READY_TIMEOUT')
877
899
  })
878
900
  })
879
901
 
880
902
  test('pluginTimeout default', t => {
881
- t.plan(2)
882
- const clock = fakeTimer.install()
903
+ t.plan(5)
904
+ const clock = fakeTimer.install({ shouldClearNativeTimers: true })
883
905
 
884
906
  const fastify = Fastify()
885
907
  fastify.register(function (app, opts, done) {
@@ -889,7 +911,11 @@ test('pluginTimeout default', t => {
889
911
 
890
912
  fastify.ready((err) => {
891
913
  t.ok(err)
892
- t.equal(err.code, 'ERR_AVVIO_PLUGIN_TIMEOUT')
914
+ t.equal(err.message,
915
+ "fastify-plugin: Plugin did not start in time: 'function (app, opts, done) { -- // default time elapsed without calling done'. You may have forgotten to call 'done' function or to resolve a Promise")
916
+ t.equal(err.code, 'FST_ERR_PLUGIN_TIMEOUT')
917
+ t.ok(err.cause)
918
+ t.equal(err.cause.code, 'AVV_ERR_READY_TIMEOUT')
893
919
  })
894
920
 
895
921
  t.teardown(clock.uninstall)
@@ -7,7 +7,7 @@ const Fastify = require('..')
7
7
  test('pretty print - static routes', t => {
8
8
  t.plan(2)
9
9
 
10
- const fastify = Fastify()
10
+ const fastify = Fastify({ exposeHeadRoutes: false })
11
11
  fastify.get('/test', () => {})
12
12
  fastify.get('/test/hello', () => {})
13
13
  fastify.get('/hello/world', () => {})
@@ -29,7 +29,7 @@ test('pretty print - static routes', t => {
29
29
  test('pretty print - parametric routes', t => {
30
30
  t.plan(2)
31
31
 
32
- const fastify = Fastify()
32
+ const fastify = Fastify({ exposeHeadRoutes: false })
33
33
  fastify.get('/test', () => {})
34
34
  fastify.get('/test/:hello', () => {})
35
35
  fastify.get('/hello/:world', () => {})
@@ -51,7 +51,7 @@ test('pretty print - parametric routes', t => {
51
51
  test('pretty print - mixed parametric routes', t => {
52
52
  t.plan(2)
53
53
 
54
- const fastify = Fastify()
54
+ const fastify = Fastify({ exposeHeadRoutes: false })
55
55
  fastify.get('/test', () => {})
56
56
  fastify.get('/test/:hello', () => {})
57
57
  fastify.post('/test/:hello', () => {})
@@ -75,7 +75,7 @@ test('pretty print - mixed parametric routes', t => {
75
75
  test('pretty print - wildcard routes', t => {
76
76
  t.plan(2)
77
77
 
78
- const fastify = Fastify()
78
+ const fastify = Fastify({ exposeHeadRoutes: false })
79
79
  fastify.get('/test', () => {})
80
80
  fastify.get('/test/*', () => {})
81
81
  fastify.get('/hello/*', () => {})
@@ -137,12 +137,14 @@ test('pretty print - commonPrefix', t => {
137
137
  const radixExpected = `└── /
138
138
  ├── hel
139
139
  │ ├── lo (GET)
140
+ │ │ lo (HEAD)
140
141
  │ └── icopter (GET)
142
+ │ icopter (HEAD)
141
143
  └── hello (PUT)
142
144
  `
143
145
  const flatExpected = `└── / (-)
144
- ├── helicopter (GET)
145
- └── hello (GET, PUT)
146
+ ├── helicopter (GET, HEAD)
147
+ └── hello (GET, PUT, HEAD)
146
148
  `
147
149
  t.equal(typeof radixTree, 'string')
148
150
  t.equal(typeof flatTree, 'string')
@@ -174,31 +176,41 @@ test('pretty print - includeMeta, includeHooks', t => {
174
176
  │ │ • (onTimeout) ["onTimeout()"]
175
177
  │ │ • (onRequest) ["anonymous()"]
176
178
  │ │ • (errorHandler) "defaultErrorHandler()"
179
+ │ │ lo (HEAD)
180
+ │ │ • (onTimeout) ["onTimeout()"]
181
+ │ │ • (onRequest) ["anonymous()"]
182
+ │ │ • (onSend) ["headRouteOnSendHandler()"]
183
+ │ │ • (errorHandler) "defaultErrorHandler()"
177
184
  │ └── icopter (GET)
178
185
  │ • (onTimeout) ["onTimeout()"]
179
186
  │ • (onRequest) ["anonymous()"]
180
187
  │ • (errorHandler) "defaultErrorHandler()"
188
+ │ icopter (HEAD)
189
+ │ • (onTimeout) ["onTimeout()"]
190
+ │ • (onRequest) ["anonymous()"]
191
+ │ • (onSend) ["headRouteOnSendHandler()"]
192
+ │ • (errorHandler) "defaultErrorHandler()"
181
193
  └── hello (PUT)
182
194
  • (onTimeout) ["onTimeout()"]
183
195
  • (onRequest) ["anonymous()"]
184
196
  • (errorHandler) "defaultErrorHandler()"
185
197
  `
186
198
  const flatExpected = `└── / (-)
187
- ├── helicopter (GET)
199
+ ├── helicopter (GET, HEAD)
188
200
  │ • (onTimeout) ["onTimeout()"]
189
201
  │ • (onRequest) ["anonymous()"]
190
202
  │ • (errorHandler) "defaultErrorHandler()"
191
- └── hello (GET, PUT)
203
+ └── hello (GET, PUT, HEAD)
192
204
  • (onTimeout) ["onTimeout()"]
193
205
  • (onRequest) ["anonymous()"]
194
206
  • (errorHandler) "defaultErrorHandler()"
195
207
  `
196
208
 
197
209
  const hooksOnlyExpected = `└── / (-)
198
- ├── helicopter (GET)
210
+ ├── helicopter (GET, HEAD)
199
211
  │ • (onTimeout) ["onTimeout()"]
200
212
  │ • (onRequest) ["anonymous()"]
201
- └── hello (GET, PUT)
213
+ └── hello (GET, PUT, HEAD)
202
214
  • (onTimeout) ["onTimeout()"]
203
215
  • (onRequest) ["anonymous()"]
204
216
  `
@@ -60,7 +60,7 @@ fastify.get('/return-reply', opts, function (req, reply) {
60
60
  return reply.send({ hello: 'world' })
61
61
  })
62
62
 
63
- fastify.listen(0, err => {
63
+ fastify.listen({ port: 0 }, err => {
64
64
  t.error(err)
65
65
  fastify.server.unref()
66
66
 
@@ -15,7 +15,7 @@ test('proto-poisoning error', t => {
15
15
  t.fail('handler should not be called')
16
16
  })
17
17
 
18
- fastify.listen(0, function (err) {
18
+ fastify.listen({ port: 0 }, function (err) {
19
19
  t.error(err)
20
20
 
21
21
  sget({
@@ -41,7 +41,7 @@ test('proto-poisoning remove', t => {
41
41
  reply.send({ ok: true })
42
42
  })
43
43
 
44
- fastify.listen(0, function (err) {
44
+ fastify.listen({ port: 0 }, function (err) {
45
45
  t.error(err)
46
46
 
47
47
  sget({
@@ -67,7 +67,7 @@ test('proto-poisoning ignore', t => {
67
67
  reply.send({ ok: true })
68
68
  })
69
69
 
70
- fastify.listen(0, function (err) {
70
+ fastify.listen({ port: 0 }, function (err) {
71
71
  t.error(err)
72
72
 
73
73
  sget({
@@ -92,7 +92,7 @@ test('constructor-poisoning error (default in v3)', t => {
92
92
  reply.send('ok')
93
93
  })
94
94
 
95
- fastify.listen(0, function (err) {
95
+ fastify.listen({ port: 0 }, function (err) {
96
96
  t.error(err)
97
97
 
98
98
  sget({
@@ -117,7 +117,7 @@ test('constructor-poisoning error', t => {
117
117
  t.fail('handler should not be called')
118
118
  })
119
119
 
120
- fastify.listen(0, function (err) {
120
+ fastify.listen({ port: 0 }, function (err) {
121
121
  t.error(err)
122
122
 
123
123
  sget({
@@ -143,7 +143,7 @@ test('constructor-poisoning remove', t => {
143
143
  reply.send({ ok: true })
144
144
  })
145
145
 
146
- fastify.listen(0, function (err) {
146
+ fastify.listen({ port: 0 }, function (err) {
147
147
  t.error(err)
148
148
 
149
149
  sget({
@@ -38,7 +38,7 @@ test('register', t => {
38
38
  done()
39
39
  })
40
40
 
41
- fastify.listen(0, err => {
41
+ fastify.listen({ port: 0 }, err => {
42
42
  t.error(err)
43
43
  fastify.server.unref()
44
44
 
@@ -71,7 +71,7 @@ test('internal route declaration should pass the error generated by the register
71
71
  reply.send({ hello: 'world' })
72
72
  })
73
73
 
74
- fastify.listen(0, err => {
74
+ fastify.listen({ port: 0 }, err => {
75
75
  fastify.close()
76
76
  t.equal(err.message, 'kaboom')
77
77
  })
@@ -93,7 +93,7 @@ test('internal route declaration should pass the error generated by the register
93
93
  t.equal(err.message, 'kaboom')
94
94
  })
95
95
 
96
- fastify.listen(0, err => {
96
+ fastify.listen({ port: 0 }, err => {
97
97
  fastify.close()
98
98
  t.error(err)
99
99
  })
@@ -107,7 +107,7 @@ test('Should reply 400 on client error', t => {
107
107
  t.plan(2)
108
108
 
109
109
  const fastify = Fastify()
110
- fastify.listen(0, err => {
110
+ fastify.listen({ port: 0 }, err => {
111
111
  t.error(err)
112
112
 
113
113
  const client = net.connect(fastify.server.address().port)
@@ -156,7 +156,7 @@ test('Should set the response from client error handler', t => {
156
156
  }
157
157
  })
158
158
 
159
- fastify.listen(0, err => {
159
+ fastify.listen({ port: 0 }, err => {
160
160
  t.error(err)
161
161
 
162
162
  const client = net.connect(fastify.server.address().port)
@@ -290,7 +290,7 @@ test('Support rejection with values that are not Error instances', t => {
290
290
  } else {
291
291
  t.equal(err, nonErr)
292
292
  }
293
- reply.send('error')
293
+ reply.code(500).send('error')
294
294
  })
295
295
 
296
296
  fastify.inject({
@@ -337,7 +337,7 @@ test('invalid schema - ajv', t => {
337
337
  })
338
338
  })
339
339
 
340
- test('should set the status code and the headers from the error object (from route handler)', t => {
340
+ test('should set the status code and the headers from the error object (from route handler) (no custom error handler)', t => {
341
341
  t.plan(4)
342
342
  const fastify = Fastify()
343
343
 
@@ -375,7 +375,7 @@ test('should set the status code and the headers from the error object (from cus
375
375
 
376
376
  fastify.setErrorHandler((err, request, reply) => {
377
377
  t.equal(err.message, 'ouch')
378
- t.equal(reply.raw.statusCode, 401)
378
+ t.equal(reply.raw.statusCode, 200)
379
379
  const error = new Error('kaboom')
380
380
  error.headers = { hello: 'world' }
381
381
  error.statusCode = 400
@@ -446,6 +446,74 @@ test('should throw an error if the custom serializer does not serialize the payl
446
446
  })
447
447
  })
448
448
 
449
+ test('should not set headers or status code for custom error handler', t => {
450
+ t.plan(7)
451
+
452
+ const fastify = Fastify()
453
+ fastify.get('/', function (req, reply) {
454
+ const err = new Error('kaboom')
455
+ err.headers = {
456
+ 'fake-random-header': 'abc'
457
+ }
458
+ reply.send(err)
459
+ })
460
+
461
+ fastify.setErrorHandler(async (err, req, res) => {
462
+ t.equal(res.statusCode, 200)
463
+ t.equal('fake-random-header' in res.headers, false)
464
+ return res.code(500).send(err.message)
465
+ })
466
+
467
+ fastify.inject({
468
+ method: 'GET',
469
+ url: '/'
470
+ }, (err, res) => {
471
+ t.error(err)
472
+ t.equal(res.statusCode, 500)
473
+ t.equal('fake-random-header' in res.headers, false)
474
+ t.equal(res.headers['content-length'], ('kaboom'.length).toString())
475
+ t.same(res.payload, 'kaboom')
476
+ })
477
+ })
478
+
479
+ test('error thrown by custom error handler routes to default error handler', t => {
480
+ t.plan(6)
481
+
482
+ const fastify = Fastify()
483
+
484
+ const error = new Error('kaboom')
485
+ error.headers = {
486
+ 'fake-random-header': 'abc'
487
+ }
488
+
489
+ fastify.get('/', function (req, reply) {
490
+ reply.send(error)
491
+ })
492
+
493
+ const newError = new Error('kabong')
494
+
495
+ fastify.setErrorHandler(async (err, req, res) => {
496
+ t.equal(res.statusCode, 200)
497
+ t.equal('fake-random-header' in res.headers, false)
498
+ t.same(err.headers, error.headers)
499
+
500
+ return res.send(newError)
501
+ })
502
+
503
+ fastify.inject({
504
+ method: 'GET',
505
+ url: '/'
506
+ }, (err, res) => {
507
+ t.error(err)
508
+ t.equal(res.statusCode, 500)
509
+ t.same(JSON.parse(res.payload), {
510
+ error: statusCodes['500'],
511
+ message: newError.message,
512
+ statusCode: 500
513
+ })
514
+ })
515
+ })
516
+
449
517
  // Issue 2078 https://github.com/fastify/fastify/issues/2078
450
518
  // Supported error code list: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
451
519
  const invalidErrorCodes = [
@@ -475,6 +543,34 @@ invalidErrorCodes.forEach((invalidCode) => {
475
543
  })
476
544
  })
477
545
 
546
+ test('error handler is triggered when a string is thrown from sync handler', t => {
547
+ t.plan(3)
548
+
549
+ const fastify = Fastify()
550
+
551
+ const throwable = 'test'
552
+ const payload = 'error'
553
+
554
+ fastify.get('/', function (req, reply) {
555
+ // eslint-disable-next-line no-throw-literal
556
+ throw throwable
557
+ })
558
+
559
+ fastify.setErrorHandler((err, req, res) => {
560
+ t.equal(err, throwable)
561
+
562
+ res.send(payload)
563
+ })
564
+
565
+ fastify.inject({
566
+ method: 'GET',
567
+ url: '/'
568
+ }, (err, res) => {
569
+ t.error(err)
570
+ t.equal(res.payload, payload)
571
+ })
572
+ })
573
+
478
574
  test('status code should be set to 500 and return an error json payload if route handler throws any non Error object expression', async t => {
479
575
  t.plan(2)
480
576
  const fastify = Fastify()
@@ -508,24 +604,39 @@ test('should preserve the status code set by the user if an expression is thrown
508
604
  })
509
605
 
510
606
  test('should trigger error handlers if a sync route throws any non-error object', async t => {
511
- t.plan(3)
607
+ t.plan(2)
512
608
 
513
609
  const fastify = Fastify()
514
610
 
515
- fastify.get('/', () => {
516
- /* eslint-disable-next-line */
517
- throw { foo: 'bar' }
611
+ const throwable = 'test'
612
+ const payload = 'error'
613
+
614
+ fastify.get('/', function async (req, reply) {
615
+ // eslint-disable-next-line no-throw-literal
616
+ throw throwable
518
617
  })
519
618
 
520
- fastify.setErrorHandler(async (error) => {
521
- t.ok(error)
522
- return error
619
+ fastify.setErrorHandler((err, req, res) => {
620
+ t.equal(err, throwable)
621
+ res.code(500).send(payload)
622
+ })
623
+
624
+ const reply = await fastify.inject({ method: 'GET', url: '/' })
625
+ t.equal(reply.statusCode, 500)
626
+ })
627
+
628
+ test('should trigger error handlers if a sync route throws undefined', async t => {
629
+ t.plan(1)
630
+
631
+ const fastify = Fastify()
632
+
633
+ fastify.get('/', function async (req, reply) {
634
+ // eslint-disable-next-line no-throw-literal
635
+ throw undefined
523
636
  })
524
637
 
525
- // ----
526
638
  const reply = await fastify.inject({ method: 'GET', url: '/' })
527
639
  t.equal(reply.statusCode, 500)
528
- t.equal(JSON.parse(reply.body).foo, 'bar')
529
640
  })
530
641
 
531
642
  test('setting content-type on reply object should not hang the server case 1', t => {
@@ -560,7 +671,7 @@ test('setting content-type on reply object should not hang the server case 2', a
560
671
  })
561
672
 
562
673
  try {
563
- await fastify.listen(0)
674
+ await fastify.listen({ port: 0 })
564
675
  const res = await fastify.inject({
565
676
  url: '/',
566
677
  method: 'GET'
@@ -43,7 +43,7 @@ test('default 400 on request error with custom error handler', t => {
43
43
 
44
44
  fastify.setErrorHandler(function (err, request, reply) {
45
45
  t.type(request, 'object')
46
- t.type(request, fastify[kRequest])
46
+ t.type(request, fastify[kRequest].parent)
47
47
  reply
48
48
  .code(err.statusCode)
49
49
  .type('application/json; charset=utf-8')
@@ -105,7 +105,7 @@ test('default clientError handler ignores ECONNRESET', t => {
105
105
  })
106
106
  })
107
107
 
108
- fastify.listen(0, function (err) {
108
+ fastify.listen({ port: 0 }, function (err) {
109
109
  t.error(err)
110
110
  fastify.server.unref()
111
111
 
@@ -132,10 +132,7 @@ test('default clientError handler ignores sockets in destroyed state', t => {
132
132
 
133
133
  const fastify = Fastify({
134
134
  bodyLimit: 1,
135
- keepAliveTimeout: 100,
136
- logger: {
137
- level: 'trace'
138
- }
135
+ keepAliveTimeout: 100
139
136
  })
140
137
  fastify.server.on('clientError', () => {
141
138
  // this handler is called after default handler, so we can make sure end was not called