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
package/test/404s.test.js CHANGED
@@ -9,8 +9,17 @@ const errors = require('http-errors')
9
9
  const split = require('split2')
10
10
  const Fastify = require('..')
11
11
 
12
+ function getUrl (app) {
13
+ const { address, port } = app.server.address()
14
+ if (address === '::1') {
15
+ return `http://[${address}]:${port}`
16
+ } else {
17
+ return `http://${address}:${port}`
18
+ }
19
+ }
20
+
12
21
  test('default 404', t => {
13
- t.plan(3)
22
+ t.plan(4)
14
23
 
15
24
  const test = t.test
16
25
  const fastify = Fastify()
@@ -21,14 +30,29 @@ test('default 404', t => {
21
30
 
22
31
  t.teardown(fastify.close.bind(fastify))
23
32
 
24
- fastify.listen(0, err => {
33
+ fastify.listen({ port: 0 }, err => {
25
34
  t.error(err)
26
35
 
27
36
  test('unsupported method', t => {
28
37
  t.plan(3)
29
38
  sget({
30
39
  method: 'PUT',
31
- url: 'http://localhost:' + fastify.server.address().port,
40
+ url: getUrl(fastify),
41
+ body: {},
42
+ json: true
43
+ }, (err, response, body) => {
44
+ t.error(err)
45
+ t.equal(response.statusCode, 404)
46
+ t.equal(response.headers['content-type'], 'application/json; charset=utf-8')
47
+ })
48
+ })
49
+
50
+ // Return 404 instead of 405 see https://github.com/fastify/fastify/pull/862 for discussion
51
+ test('framework-unsupported method', t => {
52
+ t.plan(3)
53
+ sget({
54
+ method: 'PROPFIND',
55
+ url: getUrl(fastify),
32
56
  body: {},
33
57
  json: true
34
58
  }, (err, response, body) => {
@@ -42,7 +66,7 @@ test('default 404', t => {
42
66
  t.plan(3)
43
67
  sget({
44
68
  method: 'GET',
45
- url: 'http://localhost:' + fastify.server.address().port + '/notSupported',
69
+ url: getUrl(fastify) + '/notSupported',
46
70
  body: {},
47
71
  json: true
48
72
  }, (err, response, body) => {
@@ -55,7 +79,7 @@ test('default 404', t => {
55
79
  })
56
80
 
57
81
  test('customized 404', t => {
58
- t.plan(5)
82
+ t.plan(6)
59
83
 
60
84
  const test = t.test
61
85
  const fastify = Fastify()
@@ -80,14 +104,28 @@ test('customized 404', t => {
80
104
 
81
105
  t.teardown(fastify.close.bind(fastify))
82
106
 
83
- fastify.listen(0, err => {
107
+ fastify.listen({ port: 0 }, err => {
84
108
  t.error(err)
85
109
 
86
110
  test('unsupported method', t => {
87
111
  t.plan(3)
88
112
  sget({
89
113
  method: 'PUT',
90
- url: 'http://localhost:' + fastify.server.address().port,
114
+ url: getUrl(fastify),
115
+ body: JSON.stringify({ hello: 'world' }),
116
+ headers: { 'Content-Type': 'application/json' }
117
+ }, (err, response, body) => {
118
+ t.error(err)
119
+ t.equal(response.statusCode, 404)
120
+ t.equal(body.toString(), 'this was not found')
121
+ })
122
+ })
123
+
124
+ test('framework-unsupported method', t => {
125
+ t.plan(3)
126
+ sget({
127
+ method: 'PROPFIND',
128
+ url: getUrl(fastify),
91
129
  body: JSON.stringify({ hello: 'world' }),
92
130
  headers: { 'Content-Type': 'application/json' }
93
131
  }, (err, response, body) => {
@@ -101,7 +139,7 @@ test('customized 404', t => {
101
139
  t.plan(3)
102
140
  sget({
103
141
  method: 'GET',
104
- url: 'http://localhost:' + fastify.server.address().port + '/notSupported'
142
+ url: getUrl(fastify) + '/notSupported'
105
143
  }, (err, response, body) => {
106
144
  t.error(err)
107
145
  t.equal(response.statusCode, 404)
@@ -113,7 +151,7 @@ test('customized 404', t => {
113
151
  t.plan(3)
114
152
  sget({
115
153
  method: 'GET',
116
- url: 'http://localhost:' + fastify.server.address().port + '/with-error'
154
+ url: getUrl(fastify) + '/with-error'
117
155
  }, (err, response, body) => {
118
156
  t.error(err)
119
157
  t.equal(response.statusCode, 404)
@@ -129,7 +167,7 @@ test('customized 404', t => {
129
167
  t.plan(4)
130
168
  sget({
131
169
  method: 'GET',
132
- url: 'http://localhost:' + fastify.server.address().port + '/with-error-custom-header'
170
+ url: getUrl(fastify) + '/with-error-custom-header'
133
171
  }, (err, response, body) => {
134
172
  t.error(err)
135
173
  t.equal(response.statusCode, 404)
@@ -156,14 +194,14 @@ test('custom header in notFound handler', t => {
156
194
 
157
195
  t.teardown(fastify.close.bind(fastify))
158
196
 
159
- fastify.listen(0, err => {
197
+ fastify.listen({ port: 0 }, err => {
160
198
  t.error(err)
161
199
 
162
200
  test('not found with custom header', t => {
163
201
  t.plan(4)
164
202
  sget({
165
203
  method: 'GET',
166
- url: 'http://localhost:' + fastify.server.address().port + '/notSupported'
204
+ url: getUrl(fastify) + '/notSupported'
167
205
  }, (err, response, body) => {
168
206
  t.error(err)
169
207
  t.equal(response.statusCode, 404)
@@ -212,7 +250,7 @@ test('setting a custom 404 handler multiple times is an error', t => {
212
250
  done()
213
251
  }, { prefix: '/prefix' })
214
252
 
215
- fastify.listen(0, err => {
253
+ fastify.listen({ port: 0 }, err => {
216
254
  t.error(err)
217
255
  fastify.close()
218
256
  })
@@ -236,7 +274,7 @@ test('setting a custom 404 handler multiple times is an error', t => {
236
274
 
237
275
  fastify.setNotFoundHandler(() => {})
238
276
 
239
- fastify.listen(0, err => {
277
+ fastify.listen({ port: 0 }, err => {
240
278
  t.error(err)
241
279
  fastify.close()
242
280
  })
@@ -266,7 +304,7 @@ test('setting a custom 404 handler multiple times is an error', t => {
266
304
 
267
305
  fastify.setNotFoundHandler(() => {})
268
306
 
269
- fastify.listen(0, err => {
307
+ fastify.listen({ port: 0 }, err => {
270
308
  t.error(err)
271
309
  fastify.close()
272
310
  })
@@ -299,7 +337,7 @@ test('setting a custom 404 handler multiple times is an error', t => {
299
337
 
300
338
  fastify.setNotFoundHandler(() => {})
301
339
 
302
- fastify.listen(0, err => {
340
+ fastify.listen({ port: 0 }, err => {
303
341
  t.error(err)
304
342
  fastify.close()
305
343
  })
@@ -307,7 +345,7 @@ test('setting a custom 404 handler multiple times is an error', t => {
307
345
  })
308
346
 
309
347
  test('encapsulated 404', t => {
310
- t.plan(9)
348
+ t.plan(13)
311
349
 
312
350
  const test = t.test
313
351
  const fastify = Fastify()
@@ -343,14 +381,14 @@ test('encapsulated 404', t => {
343
381
 
344
382
  t.teardown(fastify.close.bind(fastify))
345
383
 
346
- fastify.listen(0, err => {
384
+ fastify.listen({ port: 0 }, err => {
347
385
  t.error(err)
348
386
 
349
387
  test('root unsupported method', t => {
350
388
  t.plan(3)
351
389
  sget({
352
390
  method: 'PUT',
353
- url: 'http://localhost:' + fastify.server.address().port,
391
+ url: getUrl(fastify),
354
392
  body: JSON.stringify({ hello: 'world' }),
355
393
  headers: { 'Content-Type': 'application/json' }
356
394
  }, (err, response, body) => {
@@ -360,11 +398,25 @@ test('encapsulated 404', t => {
360
398
  })
361
399
  })
362
400
 
363
- test('root insupported route', t => {
401
+ test('root framework-unsupported method', t => {
402
+ t.plan(3)
403
+ sget({
404
+ method: 'PROPFIND',
405
+ url: getUrl(fastify),
406
+ body: JSON.stringify({ hello: 'world' }),
407
+ headers: { 'Content-Type': 'application/json' }
408
+ }, (err, response, body) => {
409
+ t.error(err)
410
+ t.equal(response.statusCode, 404)
411
+ t.equal(body.toString(), 'this was not found')
412
+ })
413
+ })
414
+
415
+ test('root unsupported route', t => {
364
416
  t.plan(3)
365
417
  sget({
366
418
  method: 'GET',
367
- url: 'http://localhost:' + fastify.server.address().port + '/notSupported'
419
+ url: getUrl(fastify) + '/notSupported'
368
420
  }, (err, response, body) => {
369
421
  t.error(err)
370
422
  t.equal(response.statusCode, 404)
@@ -376,7 +428,21 @@ test('encapsulated 404', t => {
376
428
  t.plan(3)
377
429
  sget({
378
430
  method: 'PUT',
379
- url: 'http://localhost:' + fastify.server.address().port + '/test',
431
+ url: getUrl(fastify) + '/test',
432
+ body: JSON.stringify({ hello: 'world' }),
433
+ headers: { 'Content-Type': 'application/json' }
434
+ }, (err, response, body) => {
435
+ t.error(err)
436
+ t.equal(response.statusCode, 404)
437
+ t.equal(body.toString(), 'this was not found 2')
438
+ })
439
+ })
440
+
441
+ test('framework-unsupported method', t => {
442
+ t.plan(3)
443
+ sget({
444
+ method: 'PROPFIND',
445
+ url: getUrl(fastify) + '/test',
380
446
  body: JSON.stringify({ hello: 'world' }),
381
447
  headers: { 'Content-Type': 'application/json' }
382
448
  }, (err, response, body) => {
@@ -390,7 +456,7 @@ test('encapsulated 404', t => {
390
456
  t.plan(3)
391
457
  sget({
392
458
  method: 'GET',
393
- url: 'http://localhost:' + fastify.server.address().port + '/test/notSupported'
459
+ url: getUrl(fastify) + '/test/notSupported'
394
460
  }, (err, response, body) => {
395
461
  t.error(err)
396
462
  t.equal(response.statusCode, 404)
@@ -398,11 +464,11 @@ test('encapsulated 404', t => {
398
464
  })
399
465
  })
400
466
 
401
- test('unsupported method bis', t => {
467
+ test('unsupported method 2', t => {
402
468
  t.plan(3)
403
469
  sget({
404
470
  method: 'PUT',
405
- url: 'http://localhost:' + fastify.server.address().port + '/test2',
471
+ url: getUrl(fastify) + '/test2',
406
472
  body: JSON.stringify({ hello: 'world' }),
407
473
  headers: { 'Content-Type': 'application/json' }
408
474
  }, (err, response, body) => {
@@ -412,11 +478,25 @@ test('encapsulated 404', t => {
412
478
  })
413
479
  })
414
480
 
415
- test('unsupported route bis', t => {
481
+ test('framework-unsupported method 2', t => {
482
+ t.plan(3)
483
+ sget({
484
+ method: 'PROPFIND',
485
+ url: getUrl(fastify) + '/test2',
486
+ body: JSON.stringify({ hello: 'world' }),
487
+ headers: { 'Content-Type': 'application/json' }
488
+ }, (err, response, body) => {
489
+ t.error(err)
490
+ t.equal(response.statusCode, 404)
491
+ t.equal(body.toString(), 'this was not found 3')
492
+ })
493
+ })
494
+
495
+ test('unsupported route 2', t => {
416
496
  t.plan(3)
417
497
  sget({
418
498
  method: 'GET',
419
- url: 'http://localhost:' + fastify.server.address().port + '/test2/notSupported'
499
+ url: getUrl(fastify) + '/test2/notSupported'
420
500
  }, (err, response, body) => {
421
501
  t.error(err)
422
502
  t.equal(response.statusCode, 404)
@@ -428,7 +508,21 @@ test('encapsulated 404', t => {
428
508
  t.plan(3)
429
509
  sget({
430
510
  method: 'PUT',
431
- url: 'http://localhost:' + fastify.server.address().port + '/test3/',
511
+ url: getUrl(fastify) + '/test3/',
512
+ body: JSON.stringify({ hello: 'world' }),
513
+ headers: { 'Content-Type': 'application/json' }
514
+ }, (err, response, body) => {
515
+ t.error(err)
516
+ t.equal(response.statusCode, 404)
517
+ t.equal(body.toString(), 'this was not found 4')
518
+ })
519
+ })
520
+
521
+ test('framework-unsupported method 3', t => {
522
+ t.plan(3)
523
+ sget({
524
+ method: 'PROPFIND',
525
+ url: getUrl(fastify) + '/test3/',
432
526
  body: JSON.stringify({ hello: 'world' }),
433
527
  headers: { 'Content-Type': 'application/json' }
434
528
  }, (err, response, body) => {
@@ -442,7 +536,7 @@ test('encapsulated 404', t => {
442
536
  t.plan(3)
443
537
  sget({
444
538
  method: 'GET',
445
- url: 'http://localhost:' + fastify.server.address().port + '/test3/notSupported'
539
+ url: getUrl(fastify) + '/test3/notSupported'
446
540
  }, (err, response, body) => {
447
541
  t.error(err)
448
542
  t.equal(response.statusCode, 404)
@@ -601,12 +695,12 @@ test('run hooks on default 404', t => {
601
695
 
602
696
  t.teardown(fastify.close.bind(fastify))
603
697
 
604
- fastify.listen(0, err => {
698
+ fastify.listen({ port: 0 }, err => {
605
699
  t.error(err)
606
700
 
607
701
  sget({
608
702
  method: 'PUT',
609
- url: 'http://localhost:' + fastify.server.address().port,
703
+ url: getUrl(fastify),
610
704
  body: JSON.stringify({ hello: 'world' }),
611
705
  headers: { 'Content-Type': 'application/json' }
612
706
  }, (err, response, body) => {
@@ -762,12 +856,82 @@ test('run hook with encapsulated 404', t => {
762
856
 
763
857
  t.teardown(fastify.close.bind(fastify))
764
858
 
765
- fastify.listen(0, err => {
859
+ fastify.listen({ port: 0 }, err => {
766
860
  t.error(err)
767
861
 
768
862
  sget({
769
863
  method: 'PUT',
770
- url: 'http://localhost:' + fastify.server.address().port + '/test',
864
+ url: getUrl(fastify) + '/test',
865
+ body: JSON.stringify({ hello: 'world' }),
866
+ headers: { 'Content-Type': 'application/json' }
867
+ }, (err, response, body) => {
868
+ t.error(err)
869
+ t.equal(response.statusCode, 404)
870
+ })
871
+ })
872
+ })
873
+
874
+ test('run hook with encapsulated 404 and framework-unsupported method', t => {
875
+ t.plan(11)
876
+
877
+ const fastify = Fastify()
878
+
879
+ fastify.addHook('onRequest', function (req, res, done) {
880
+ t.pass('onRequest called')
881
+ done()
882
+ })
883
+
884
+ fastify.addHook('preHandler', function (request, reply, done) {
885
+ t.pass('preHandler called')
886
+ done()
887
+ })
888
+
889
+ fastify.addHook('onSend', function (request, reply, payload, done) {
890
+ t.pass('onSend called')
891
+ done()
892
+ })
893
+
894
+ fastify.addHook('onResponse', function (request, reply, done) {
895
+ t.pass('onResponse called')
896
+ done()
897
+ })
898
+
899
+ fastify.register(function (f, opts, done) {
900
+ f.setNotFoundHandler(function (req, reply) {
901
+ reply.code(404).send('this was not found 2')
902
+ })
903
+
904
+ f.addHook('onRequest', function (req, res, done) {
905
+ t.pass('onRequest 2 called')
906
+ done()
907
+ })
908
+
909
+ f.addHook('preHandler', function (request, reply, done) {
910
+ t.pass('preHandler 2 called')
911
+ done()
912
+ })
913
+
914
+ f.addHook('onSend', function (request, reply, payload, done) {
915
+ t.pass('onSend 2 called')
916
+ done()
917
+ })
918
+
919
+ f.addHook('onResponse', function (request, reply, done) {
920
+ t.pass('onResponse 2 called')
921
+ done()
922
+ })
923
+
924
+ done()
925
+ }, { prefix: '/test' })
926
+
927
+ t.teardown(fastify.close.bind(fastify))
928
+
929
+ fastify.listen({ port: 0 }, err => {
930
+ t.error(err)
931
+
932
+ sget({
933
+ method: 'PROPFIND',
934
+ url: getUrl(fastify) + '/test',
771
935
  body: JSON.stringify({ hello: 'world' }),
772
936
  headers: { 'Content-Type': 'application/json' }
773
937
  }, (err, response, body) => {
@@ -802,12 +966,12 @@ test('hooks check 404', t => {
802
966
 
803
967
  t.teardown(fastify.close.bind(fastify))
804
968
 
805
- fastify.listen(0, err => {
969
+ fastify.listen({ port: 0 }, err => {
806
970
  t.error(err)
807
971
 
808
972
  sget({
809
973
  method: 'PUT',
810
- url: 'http://localhost:' + fastify.server.address().port + '?foo=asd',
974
+ url: getUrl(fastify) + '?foo=asd',
811
975
  body: JSON.stringify({ hello: 'world' }),
812
976
  headers: { 'Content-Type': 'application/json' }
813
977
  }, (err, response, body) => {
@@ -817,7 +981,7 @@ test('hooks check 404', t => {
817
981
 
818
982
  sget({
819
983
  method: 'GET',
820
- url: 'http://localhost:' + fastify.server.address().port + '/notSupported?foo=asd'
984
+ url: getUrl(fastify) + '/notSupported?foo=asd'
821
985
  }, (err, response, body) => {
822
986
  t.error(err)
823
987
  t.equal(response.statusCode, 404)
@@ -830,21 +994,21 @@ test('setNotFoundHandler should not suppress duplicated routes checking', t => {
830
994
 
831
995
  const fastify = Fastify()
832
996
 
833
- fastify.get('/', function (req, reply) {
834
- reply.send({ hello: 'world' })
835
- })
836
-
837
- fastify.get('/', function (req, reply) {
838
- reply.send({ hello: 'world' })
839
- })
840
-
841
- fastify.setNotFoundHandler(function (req, reply) {
842
- reply.code(404).send('this was not found')
843
- })
997
+ try {
998
+ fastify.get('/', function (req, reply) {
999
+ reply.send({ hello: 'world' })
1000
+ })
1001
+ fastify.get('/', function (req, reply) {
1002
+ reply.send({ hello: 'world' })
1003
+ })
1004
+ fastify.setNotFoundHandler(function (req, reply) {
1005
+ reply.code(404).send('this was not found')
1006
+ })
844
1007
 
845
- fastify.listen(0, err => {
846
- t.ok(err)
847
- })
1008
+ t.fail('setNotFoundHandler should not interfere duplicated route error')
1009
+ } catch (error) {
1010
+ t.ok(error)
1011
+ }
848
1012
  })
849
1013
 
850
1014
  test('log debug for 404', t => {
@@ -902,7 +1066,7 @@ test('Unknown method', t => {
902
1066
 
903
1067
  t.teardown(fastify.close.bind(fastify))
904
1068
 
905
- fastify.listen(0, err => {
1069
+ fastify.listen({ port: 0 }, err => {
906
1070
  t.error(err)
907
1071
 
908
1072
  const handler = () => {}
@@ -914,7 +1078,7 @@ test('Unknown method', t => {
914
1078
 
915
1079
  sget({
916
1080
  method: 'UNKNWON_METHOD',
917
- url: 'http://localhost:' + fastify.server.address().port
1081
+ url: getUrl(fastify)
918
1082
  }, (err, response, body) => {
919
1083
  t.error(err)
920
1084
  t.equal(response.statusCode, 400)
@@ -938,7 +1102,7 @@ test('recognizes errors from the http-errors module', t => {
938
1102
 
939
1103
  t.teardown(fastify.close.bind(fastify))
940
1104
 
941
- fastify.listen(0, err => {
1105
+ fastify.listen({ port: 0 }, err => {
942
1106
  t.error(err)
943
1107
 
944
1108
  fastify.inject({
@@ -948,7 +1112,7 @@ test('recognizes errors from the http-errors module', t => {
948
1112
  t.error(err)
949
1113
  t.equal(res.statusCode, 404)
950
1114
 
951
- sget('http://localhost:' + fastify.server.address().port, (err, response, body) => {
1115
+ sget(getUrl(fastify), (err, response, body) => {
952
1116
  t.error(err)
953
1117
  const obj = JSON.parse(body.toString())
954
1118
  t.strictSame(obj, {
@@ -1056,7 +1220,7 @@ test('cannot set notFoundHandler after binding', t => {
1056
1220
  const fastify = Fastify()
1057
1221
  t.teardown(fastify.close.bind(fastify))
1058
1222
 
1059
- fastify.listen(0, err => {
1223
+ fastify.listen({ port: 0 }, err => {
1060
1224
  t.error(err)
1061
1225
 
1062
1226
  try {
@@ -1090,12 +1254,12 @@ test('404 inside onSend', t => {
1090
1254
 
1091
1255
  t.teardown(fastify.close.bind(fastify))
1092
1256
 
1093
- fastify.listen(0, err => {
1257
+ fastify.listen({ port: 0 }, err => {
1094
1258
  t.error(err)
1095
1259
 
1096
1260
  sget({
1097
1261
  method: 'GET',
1098
- url: 'http://localhost:' + fastify.server.address().port
1262
+ url: getUrl(fastify)
1099
1263
  }, (err, response, body) => {
1100
1264
  t.error(err)
1101
1265
  t.equal(response.statusCode, 404)
@@ -1103,71 +1267,6 @@ test('404 inside onSend', t => {
1103
1267
  })
1104
1268
  })
1105
1269
 
1106
- test('Not found on supported method (should return a 404)', t => {
1107
- t.plan(5)
1108
-
1109
- const fastify = Fastify()
1110
-
1111
- fastify.get('/', function (req, reply) {
1112
- reply.send({ hello: 'world' })
1113
- })
1114
-
1115
- t.teardown(fastify.close.bind(fastify))
1116
-
1117
- fastify.listen(0, err => {
1118
- t.error(err)
1119
-
1120
- fastify.inject({
1121
- method: 'POST',
1122
- url: '/'
1123
- }, (err, res) => {
1124
- t.error(err)
1125
- t.equal(res.statusCode, 404)
1126
-
1127
- sget({
1128
- method: 'POST',
1129
- url: 'http://localhost:' + fastify.server.address().port
1130
- }, (err, response, body) => {
1131
- t.error(err)
1132
- t.equal(response.statusCode, 404)
1133
- })
1134
- })
1135
- })
1136
- })
1137
-
1138
- // Return 404 instead of 405 see https://github.com/fastify/fastify/pull/862 for discussion
1139
- test('Not found on unsupported method (should return a 404)', t => {
1140
- t.plan(5)
1141
-
1142
- const fastify = Fastify()
1143
-
1144
- fastify.all('/', function (req, reply) {
1145
- reply.send({ hello: 'world' })
1146
- })
1147
-
1148
- t.teardown(fastify.close.bind(fastify))
1149
-
1150
- fastify.listen(0, err => {
1151
- t.error(err)
1152
-
1153
- fastify.inject({
1154
- method: 'PROPFIND',
1155
- url: '/'
1156
- }, (err, res) => {
1157
- t.error(err)
1158
- t.equal(res.statusCode, 404)
1159
-
1160
- sget({
1161
- method: 'PROPFIND',
1162
- url: 'http://localhost:' + fastify.server.address().port
1163
- }, (err, response, body) => {
1164
- t.error(err)
1165
- t.equal(response.statusCode, 404)
1166
- })
1167
- })
1168
- })
1169
- })
1170
-
1171
1270
  // https://github.com/fastify/fastify/issues/868
1172
1271
  test('onSend hooks run when an encapsulated route invokes the notFound handler', t => {
1173
1272
  t.plan(3)
@@ -1714,7 +1813,7 @@ test('400 in case of bad url (pre find-my-way v2.2.0 was a 404)', t => {
1714
1813
  t.equal(response.statusCode, 400)
1715
1814
  t.same(JSON.parse(response.payload), {
1716
1815
  error: 'Bad Request',
1717
- message: "'%world' is not a valid url component",
1816
+ message: "'/hello/%world' is not a valid url component",
1718
1817
  statusCode: 400
1719
1818
  })
1720
1819
  })
@@ -1738,6 +1837,41 @@ test('400 in case of bad url (pre find-my-way v2.2.0 was a 404)', t => {
1738
1837
  })
1739
1838
  })
1740
1839
 
1840
+ t.test('No route registered', t => {
1841
+ t.plan(3)
1842
+ const fastify = Fastify()
1843
+ fastify.inject({
1844
+ url: '/%c0',
1845
+ method: 'GET'
1846
+ }, (err, response) => {
1847
+ t.error(err)
1848
+ t.equal(response.statusCode, 404)
1849
+ t.same(JSON.parse(response.payload), {
1850
+ error: 'Not Found',
1851
+ message: 'Route GET:/%c0 not found',
1852
+ statusCode: 404
1853
+ })
1854
+ })
1855
+ })
1856
+
1857
+ t.test('Only / is registered', t => {
1858
+ t.plan(3)
1859
+ const fastify = Fastify()
1860
+ fastify.get('/', () => t.fail('we should not be here'))
1861
+ fastify.inject({
1862
+ url: '/non-existing',
1863
+ method: 'GET'
1864
+ }, (err, response) => {
1865
+ t.error(err)
1866
+ t.equal(response.statusCode, 404)
1867
+ t.same(JSON.parse(response.payload), {
1868
+ error: 'Not Found',
1869
+ message: 'Route GET:/non-existing not found',
1870
+ statusCode: 404
1871
+ })
1872
+ })
1873
+ })
1874
+
1741
1875
  t.end()
1742
1876
  })
1743
1877
 
@@ -1777,9 +1911,8 @@ test('Send 404 when frameworkError calls reply.callNotFound', t => {
1777
1911
  t.test('Dynamic route', t => {
1778
1912
  t.plan(4)
1779
1913
  const fastify = Fastify({
1780
- logger: true,
1781
1914
  frameworkErrors: (error, req, reply) => {
1782
- t.equal(error.message, "'%world' is not a valid url component")
1915
+ t.equal(error.message, "'/hello/%world' is not a valid url component")
1783
1916
  return reply.callNotFound()
1784
1917
  }
1785
1918
  })