fastify 4.23.2 → 4.24.1

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 (91) hide show
  1. package/README.md +1 -1
  2. package/docs/Guides/Ecosystem.md +6 -0
  3. package/docs/Reference/Hooks.md +1 -0
  4. package/docs/Reference/Plugins.md +1 -1
  5. package/docs/Reference/Reply.md +4 -3
  6. package/docs/Reference/Request.md +3 -2
  7. package/docs/Reference/Server.md +31 -3
  8. package/docs/Reference/Type-Providers.md +2 -2
  9. package/docs/Reference/TypeScript.md +21 -7
  10. package/fastify.d.ts +2 -2
  11. package/fastify.js +8 -1
  12. package/lib/contentTypeParser.js +1 -1
  13. package/lib/reply.js +20 -3
  14. package/lib/reqIdGenFactory.js +15 -9
  15. package/lib/request.js +1 -1
  16. package/lib/route.js +28 -7
  17. package/lib/schemas.js +3 -3
  18. package/lib/warnings.js +3 -1
  19. package/package.json +33 -33
  20. package/test/404s.test.js +31 -39
  21. package/test/async-await.test.js +1 -1
  22. package/test/async-dispose.test.js +21 -0
  23. package/test/build-certificate.js +90 -1
  24. package/test/close-pipelining.test.js +5 -5
  25. package/test/close.test.js +1 -5
  26. package/test/constrained-routes.test.js +127 -3
  27. package/test/custom-http-server.test.js +94 -91
  28. package/test/custom-parser.0.test.js +21 -47
  29. package/test/custom-parser.1.test.js +10 -732
  30. package/test/custom-parser.2.test.js +102 -0
  31. package/test/custom-parser.3.test.js +245 -0
  32. package/test/custom-parser.4.test.js +239 -0
  33. package/test/custom-parser.5.test.js +149 -0
  34. package/test/head.test.js +204 -0
  35. package/test/helper.js +30 -8
  36. package/test/hooks-async.test.js +163 -13
  37. package/test/hooks.on-listen.test.js +7 -6
  38. package/test/hooks.test.js +4 -15
  39. package/test/http2/closing.test.js +7 -15
  40. package/test/https/custom-https-server.test.js +43 -40
  41. package/test/input-validation.js +3 -3
  42. package/test/internals/reply.test.js +33 -4
  43. package/test/listen.1.test.js +101 -0
  44. package/test/listen.2.test.js +103 -0
  45. package/test/listen.3.test.js +87 -0
  46. package/test/listen.4.test.js +164 -0
  47. package/test/listen.deprecated.test.js +3 -9
  48. package/test/logger/instantiation.test.js +347 -0
  49. package/test/logger/logger-test-utils.js +47 -0
  50. package/test/logger/logging.test.js +406 -0
  51. package/test/logger/options.test.js +500 -0
  52. package/test/logger/request.test.js +292 -0
  53. package/test/logger/response.test.js +184 -0
  54. package/test/plugin.1.test.js +249 -0
  55. package/test/plugin.2.test.js +328 -0
  56. package/test/plugin.3.test.js +311 -0
  57. package/test/plugin.4.test.js +416 -0
  58. package/test/reply-code.test.js +64 -0
  59. package/test/reply-trailers.test.js +1 -2
  60. package/test/route.1.test.js +309 -0
  61. package/test/route.2.test.js +99 -0
  62. package/test/route.3.test.js +205 -0
  63. package/test/route.4.test.js +131 -0
  64. package/test/route.5.test.js +230 -0
  65. package/test/route.6.test.js +306 -0
  66. package/test/route.7.test.js +370 -0
  67. package/test/route.8.test.js +142 -0
  68. package/test/stream.1.test.js +108 -0
  69. package/test/stream.2.test.js +119 -0
  70. package/test/stream.3.test.js +192 -0
  71. package/test/stream.4.test.js +223 -0
  72. package/test/stream.5.test.js +194 -0
  73. package/test/trust-proxy.test.js +2 -4
  74. package/test/types/reply.test-d.ts +3 -3
  75. package/test/types/request.test-d.ts +9 -9
  76. package/test/types/type-provider.test-d.ts +89 -0
  77. package/test/types/using.test-d.ts +14 -0
  78. package/test/upgrade.test.js +3 -3
  79. package/types/context.d.ts +9 -2
  80. package/types/instance.d.ts +4 -1
  81. package/types/plugin.d.ts +2 -1
  82. package/types/reply.d.ts +2 -2
  83. package/types/request.d.ts +3 -3
  84. package/types/route.d.ts +5 -5
  85. package/test/listen.test.js +0 -427
  86. package/test/plugin.test.js +0 -1275
  87. package/test/route.test.js +0 -1762
  88. package/test/serial/logger.0.test.js +0 -866
  89. package/test/serial/logger.1.test.js +0 -862
  90. package/test/stream.test.js +0 -816
  91. /package/test/{serial → logger}/tap-parallel-not-ok +0 -0
@@ -57,3 +57,67 @@ test('code should handle null/undefined/float', t => {
57
57
  t.equal(res.statusCode, 404)
58
58
  })
59
59
  })
60
+
61
+ test('code should handle 204', t => {
62
+ t.plan(8)
63
+
64
+ const fastify = Fastify()
65
+
66
+ fastify.get('/204', function (request, reply) {
67
+ reply.status(204)
68
+ return null
69
+ })
70
+
71
+ fastify.get('/undefined/204', function (request, reply) {
72
+ reply.status(204).send({ message: 'hello' })
73
+ })
74
+
75
+ fastify.inject({
76
+ method: 'GET',
77
+ url: '/204'
78
+ }, (error, res) => {
79
+ t.error(error)
80
+ t.equal(res.statusCode, 204)
81
+ t.equal(res.payload, '')
82
+ t.equal(res.headers['content-length'], undefined)
83
+ })
84
+
85
+ fastify.inject({
86
+ method: 'GET',
87
+ url: '/undefined/204'
88
+ }, (error, res) => {
89
+ t.error(error)
90
+ t.equal(res.statusCode, 204)
91
+ t.equal(res.payload, '')
92
+ t.equal(res.headers['content-length'], undefined)
93
+ })
94
+ })
95
+
96
+ test('code should handle onSend hook on 204', t => {
97
+ t.plan(5)
98
+
99
+ const fastify = Fastify()
100
+ fastify.addHook('onSend', async function (request, reply, payload) {
101
+ return {
102
+ ...payload,
103
+ world: 'hello'
104
+ }
105
+ })
106
+
107
+ fastify.get('/204', function (request, reply) {
108
+ reply.status(204).send({
109
+ hello: 'world'
110
+ })
111
+ })
112
+
113
+ fastify.inject({
114
+ method: 'GET',
115
+ url: '/204'
116
+ }, (error, res) => {
117
+ t.error(error)
118
+ t.equal(res.statusCode, 204)
119
+ t.equal(res.payload, '')
120
+ t.equal(res.headers['content-length'], undefined)
121
+ t.equal(res.headers['content-type'], undefined)
122
+ })
123
+ })
@@ -5,8 +5,7 @@ const test = t.test
5
5
  const Fastify = require('..')
6
6
  const { Readable } = require('node:stream')
7
7
  const { createHash } = require('node:crypto')
8
- const { promisify } = require('node:util')
9
- const sleep = promisify(setTimeout)
8
+ const { sleep } = require('./helper')
10
9
 
11
10
  test('send trailers when payload is empty string', t => {
12
11
  t.plan(5)
@@ -0,0 +1,309 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const test = t.test
5
+ const sget = require('simple-get').concat
6
+ const Fastify = require('..')
7
+ const {
8
+ FST_ERR_INSTANCE_ALREADY_LISTENING,
9
+ FST_ERR_ROUTE_METHOD_INVALID
10
+ } = require('../lib/errors')
11
+ const { getServerUrl } = require('./helper')
12
+
13
+ test('route', t => {
14
+ t.plan(10)
15
+ const test = t.test
16
+
17
+ test('route - get', t => {
18
+ t.plan(4)
19
+
20
+ const fastify = Fastify()
21
+ t.doesNotThrow(() =>
22
+ fastify.route({
23
+ method: 'GET',
24
+ url: '/',
25
+ schema: {
26
+ response: {
27
+ '2xx': {
28
+ type: 'object',
29
+ properties: {
30
+ hello: {
31
+ type: 'string'
32
+ }
33
+ }
34
+ }
35
+ }
36
+ },
37
+ handler: function (req, reply) {
38
+ reply.send({ hello: 'world' })
39
+ }
40
+ })
41
+ )
42
+
43
+ fastify.listen({ port: 0 }, function (err) {
44
+ if (err) t.error(err)
45
+ t.teardown(() => { fastify.close() })
46
+ sget({
47
+ method: 'GET',
48
+ url: getServerUrl(fastify) + '/'
49
+ }, (err, response, body) => {
50
+ t.error(err)
51
+ t.equal(response.statusCode, 200)
52
+ t.same(JSON.parse(body), { hello: 'world' })
53
+ })
54
+ })
55
+ })
56
+
57
+ test('missing schema - route', t => {
58
+ t.plan(4)
59
+
60
+ const fastify = Fastify()
61
+ t.doesNotThrow(() =>
62
+ fastify.route({
63
+ method: 'GET',
64
+ url: '/missing',
65
+ handler: function (req, reply) {
66
+ reply.send({ hello: 'world' })
67
+ }
68
+ })
69
+ )
70
+
71
+ fastify.listen({ port: 0 }, function (err) {
72
+ if (err) t.error(err)
73
+ t.teardown(() => { fastify.close() })
74
+ sget({
75
+ method: 'GET',
76
+ url: getServerUrl(fastify) + '/missing'
77
+ }, (err, response, body) => {
78
+ t.error(err)
79
+ t.equal(response.statusCode, 200)
80
+ t.same(JSON.parse(body), { hello: 'world' })
81
+ })
82
+ })
83
+ })
84
+
85
+ test('invalid handler attribute - route', t => {
86
+ t.plan(1)
87
+
88
+ const fastify = Fastify()
89
+ t.throws(() => fastify.get('/', { handler: 'not a function' }, () => { }))
90
+ })
91
+
92
+ test('Add Multiple methods per route all uppercase', t => {
93
+ t.plan(7)
94
+
95
+ const fastify = Fastify()
96
+ t.doesNotThrow(() =>
97
+ fastify.route({
98
+ method: ['GET', 'DELETE'],
99
+ url: '/multiple',
100
+ handler: function (req, reply) {
101
+ reply.send({ hello: 'world' })
102
+ }
103
+ }))
104
+
105
+ fastify.listen({ port: 0 }, function (err) {
106
+ if (err) t.error(err)
107
+ t.teardown(() => { fastify.close() })
108
+ sget({
109
+ method: 'GET',
110
+ url: getServerUrl(fastify) + '/multiple'
111
+ }, (err, response, body) => {
112
+ t.error(err)
113
+ t.equal(response.statusCode, 200)
114
+ t.same(JSON.parse(body), { hello: 'world' })
115
+ })
116
+
117
+ sget({
118
+ method: 'DELETE',
119
+ url: getServerUrl(fastify) + '/multiple'
120
+ }, (err, response, body) => {
121
+ t.error(err)
122
+ t.equal(response.statusCode, 200)
123
+ t.same(JSON.parse(body), { hello: 'world' })
124
+ })
125
+ })
126
+ })
127
+
128
+ test('Add Multiple methods per route all lowercase', t => {
129
+ t.plan(7)
130
+
131
+ const fastify = Fastify()
132
+ t.doesNotThrow(() =>
133
+ fastify.route({
134
+ method: ['get', 'delete'],
135
+ url: '/multiple',
136
+ handler: function (req, reply) {
137
+ reply.send({ hello: 'world' })
138
+ }
139
+ }))
140
+
141
+ fastify.listen({ port: 0 }, function (err) {
142
+ if (err) t.error(err)
143
+ t.teardown(() => { fastify.close() })
144
+ sget({
145
+ method: 'GET',
146
+ url: getServerUrl(fastify) + '/multiple'
147
+ }, (err, response, body) => {
148
+ t.error(err)
149
+ t.equal(response.statusCode, 200)
150
+ t.same(JSON.parse(body), { hello: 'world' })
151
+ })
152
+
153
+ sget({
154
+ method: 'DELETE',
155
+ url: getServerUrl(fastify) + '/multiple'
156
+ }, (err, response, body) => {
157
+ t.error(err)
158
+ t.equal(response.statusCode, 200)
159
+ t.same(JSON.parse(body), { hello: 'world' })
160
+ })
161
+ })
162
+ })
163
+
164
+ test('Add Multiple methods per route mixed uppercase and lowercase', t => {
165
+ t.plan(7)
166
+
167
+ const fastify = Fastify()
168
+ t.doesNotThrow(() =>
169
+ fastify.route({
170
+ method: ['GET', 'delete'],
171
+ url: '/multiple',
172
+ handler: function (req, reply) {
173
+ reply.send({ hello: 'world' })
174
+ }
175
+ }))
176
+
177
+ fastify.listen({ port: 0 }, function (err) {
178
+ if (err) t.error(err)
179
+ t.teardown(() => { fastify.close() })
180
+ sget({
181
+ method: 'GET',
182
+ url: getServerUrl(fastify) + '/multiple'
183
+ }, (err, response, body) => {
184
+ t.error(err)
185
+ t.equal(response.statusCode, 200)
186
+ t.same(JSON.parse(body), { hello: 'world' })
187
+ })
188
+
189
+ sget({
190
+ method: 'DELETE',
191
+ url: getServerUrl(fastify) + '/multiple'
192
+ }, (err, response, body) => {
193
+ t.error(err)
194
+ t.equal(response.statusCode, 200)
195
+ t.same(JSON.parse(body), { hello: 'world' })
196
+ })
197
+ })
198
+ })
199
+
200
+ test('Add invalid Multiple methods per route', t => {
201
+ t.plan(1)
202
+
203
+ const fastify = Fastify()
204
+ t.throws(() =>
205
+ fastify.route({
206
+ method: ['GET', 1],
207
+ url: '/invalid-method',
208
+ handler: function (req, reply) {
209
+ reply.send({ hello: 'world' })
210
+ }
211
+ }), new FST_ERR_ROUTE_METHOD_INVALID())
212
+ })
213
+
214
+ test('Add method', t => {
215
+ t.plan(1)
216
+
217
+ const fastify = Fastify()
218
+ t.throws(() =>
219
+ fastify.route({
220
+ method: 1,
221
+ url: '/invalid-method',
222
+ handler: function (req, reply) {
223
+ reply.send({ hello: 'world' })
224
+ }
225
+ }), new FST_ERR_ROUTE_METHOD_INVALID())
226
+ })
227
+
228
+ test('Add additional multiple methods to existing route', t => {
229
+ t.plan(7)
230
+
231
+ const fastify = Fastify()
232
+ t.doesNotThrow(() => {
233
+ fastify.get('/add-multiple', function (req, reply) {
234
+ reply.send({ hello: 'Bob!' })
235
+ })
236
+ fastify.route({
237
+ method: ['PUT', 'DELETE'],
238
+ url: '/add-multiple',
239
+ handler: function (req, reply) {
240
+ reply.send({ hello: 'world' })
241
+ }
242
+ })
243
+ })
244
+
245
+ fastify.listen({ port: 0 }, function (err) {
246
+ if (err) t.error(err)
247
+ t.teardown(() => { fastify.close() })
248
+ sget({
249
+ method: 'PUT',
250
+ url: getServerUrl(fastify) + '/add-multiple'
251
+ }, (err, response, body) => {
252
+ t.error(err)
253
+ t.equal(response.statusCode, 200)
254
+ t.same(JSON.parse(body), { hello: 'world' })
255
+ })
256
+
257
+ sget({
258
+ method: 'DELETE',
259
+ url: getServerUrl(fastify) + '/add-multiple'
260
+ }, (err, response, body) => {
261
+ t.error(err)
262
+ t.equal(response.statusCode, 200)
263
+ t.same(JSON.parse(body), { hello: 'world' })
264
+ })
265
+ })
266
+ })
267
+
268
+ test('cannot add another route after binding', t => {
269
+ t.plan(1)
270
+
271
+ const fastify = Fastify()
272
+
273
+ fastify.listen({ port: 0 }, function (err) {
274
+ if (err) t.error(err)
275
+ t.teardown(() => { fastify.close() })
276
+
277
+ t.throws(() => fastify.route({
278
+ method: 'GET',
279
+ url: '/another-get-route',
280
+ handler: function (req, reply) {
281
+ reply.send({ hello: 'world' })
282
+ }
283
+ }), new FST_ERR_INSTANCE_ALREADY_LISTENING('Cannot add route!'))
284
+ })
285
+ })
286
+ })
287
+
288
+ test('invalid schema - route', t => {
289
+ t.plan(3)
290
+
291
+ const fastify = Fastify()
292
+ fastify.route({
293
+ handler: () => { },
294
+ method: 'GET',
295
+ url: '/invalid',
296
+ schema: {
297
+ querystring: {
298
+ id: 'string'
299
+ }
300
+ }
301
+ })
302
+ fastify.after(err => {
303
+ t.notOk(err, 'the error is throw on preReady')
304
+ })
305
+ fastify.ready(err => {
306
+ t.equal(err.code, 'FST_ERR_SCH_VALIDATION_BUILD')
307
+ t.match(err.message, /Failed building the validation schema for GET: \/invalid/)
308
+ })
309
+ })
@@ -0,0 +1,99 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const test = t.test
5
+ const Fastify = require('../fastify')
6
+
7
+ test('same route definition object on multiple prefixes', async t => {
8
+ t.plan(2)
9
+
10
+ const routeObject = {
11
+ handler: () => { },
12
+ method: 'GET',
13
+ url: '/simple'
14
+ }
15
+
16
+ const fastify = Fastify({ exposeHeadRoutes: false })
17
+
18
+ fastify.register(async function (f) {
19
+ f.addHook('onRoute', (routeOptions) => {
20
+ t.equal(routeOptions.url, '/v1/simple')
21
+ })
22
+ f.route(routeObject)
23
+ }, { prefix: '/v1' })
24
+ fastify.register(async function (f) {
25
+ f.addHook('onRoute', (routeOptions) => {
26
+ t.equal(routeOptions.url, '/v2/simple')
27
+ })
28
+ f.route(routeObject)
29
+ }, { prefix: '/v2' })
30
+
31
+ await fastify.ready()
32
+ })
33
+
34
+ test('path can be specified in place of uri', t => {
35
+ t.plan(3)
36
+ const fastify = Fastify()
37
+
38
+ fastify.route({
39
+ method: 'GET',
40
+ path: '/path',
41
+ handler: function (req, reply) {
42
+ reply.send({ hello: 'world' })
43
+ }
44
+ })
45
+
46
+ const reqOpts = {
47
+ method: 'GET',
48
+ url: '/path'
49
+ }
50
+
51
+ fastify.inject(reqOpts, (err, res) => {
52
+ t.error(err)
53
+ t.equal(res.statusCode, 200)
54
+ t.same(JSON.parse(res.payload), { hello: 'world' })
55
+ })
56
+ })
57
+
58
+ test('invalid bodyLimit option - route', t => {
59
+ t.plan(2)
60
+ const fastify = Fastify()
61
+
62
+ try {
63
+ fastify.route({
64
+ bodyLimit: false,
65
+ method: 'PUT',
66
+ handler: () => null
67
+ })
68
+ t.fail('bodyLimit must be an integer')
69
+ } catch (err) {
70
+ t.equal(err.message, "'bodyLimit' option must be an integer > 0. Got 'false'")
71
+ }
72
+
73
+ try {
74
+ fastify.post('/url', { bodyLimit: 10000.1 }, () => null)
75
+ t.fail('bodyLimit must be an integer')
76
+ } catch (err) {
77
+ t.equal(err.message, "'bodyLimit' option must be an integer > 0. Got '10000.1'")
78
+ }
79
+ })
80
+
81
+ test('handler function in options of shorthand route should works correctly', t => {
82
+ t.plan(3)
83
+
84
+ const fastify = Fastify()
85
+ fastify.get('/foo', {
86
+ handler: (req, reply) => {
87
+ reply.send({ hello: 'world' })
88
+ }
89
+ })
90
+
91
+ fastify.inject({
92
+ method: 'GET',
93
+ url: '/foo'
94
+ }, (err, res) => {
95
+ t.error(err)
96
+ t.equal(res.statusCode, 200)
97
+ t.same(JSON.parse(res.payload), { hello: 'world' })
98
+ })
99
+ })
@@ -0,0 +1,205 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const test = t.test
5
+ const joi = require('joi')
6
+ const Fastify = require('..')
7
+
8
+ test('does not mutate joi schemas', t => {
9
+ t.plan(4)
10
+
11
+ const fastify = Fastify()
12
+ function validatorCompiler ({ schema, method, url, httpPart }) {
13
+ // Needed to extract the params part,
14
+ // without the JSON-schema encapsulation
15
+ // that is automatically added by the short
16
+ // form of params.
17
+ schema = joi.object(schema.properties)
18
+
19
+ return validateHttpData
20
+
21
+ function validateHttpData (data) {
22
+ return schema.validate(data)
23
+ }
24
+ }
25
+
26
+ fastify.setValidatorCompiler(validatorCompiler)
27
+
28
+ fastify.route({
29
+ path: '/foo/:an_id',
30
+ method: 'GET',
31
+ schema: {
32
+ params: { an_id: joi.number() }
33
+ },
34
+ handler (req, res) {
35
+ t.same(req.params, { an_id: 42 })
36
+ res.send({ hello: 'world' })
37
+ }
38
+ })
39
+
40
+ fastify.inject({
41
+ method: 'GET',
42
+ url: '/foo/42'
43
+ }, (err, result) => {
44
+ t.error(err)
45
+ t.equal(result.statusCode, 200)
46
+ t.same(JSON.parse(result.payload), { hello: 'world' })
47
+ })
48
+ })
49
+
50
+ test('multiple routes with one schema', t => {
51
+ t.plan(2)
52
+
53
+ const fastify = Fastify()
54
+
55
+ const schema = {
56
+ query: {
57
+ id: { type: 'number' }
58
+ }
59
+ }
60
+
61
+ fastify.route({
62
+ schema,
63
+ method: 'GET',
64
+ path: '/first/:id',
65
+ handler (req, res) {
66
+ res.send({ hello: 'world' })
67
+ }
68
+ })
69
+
70
+ fastify.route({
71
+ schema,
72
+ method: 'GET',
73
+ path: '/second/:id',
74
+ handler (req, res) {
75
+ res.send({ hello: 'world' })
76
+ }
77
+ })
78
+
79
+ fastify.ready(error => {
80
+ t.error(error)
81
+ t.same(schema, schema)
82
+ })
83
+ })
84
+
85
+ test('route error handler overrides default error handler', t => {
86
+ t.plan(4)
87
+
88
+ const fastify = Fastify()
89
+
90
+ const customRouteErrorHandler = (error, request, reply) => {
91
+ t.equal(error.message, 'Wrong Pot Error')
92
+
93
+ reply.code(418).send({
94
+ message: 'Make a brew',
95
+ statusCode: 418,
96
+ error: 'Wrong Pot Error'
97
+ })
98
+ }
99
+
100
+ fastify.route({
101
+ method: 'GET',
102
+ path: '/coffee',
103
+ handler: (req, res) => {
104
+ res.send(new Error('Wrong Pot Error'))
105
+ },
106
+ errorHandler: customRouteErrorHandler
107
+ })
108
+
109
+ fastify.inject({
110
+ method: 'GET',
111
+ url: '/coffee'
112
+ }, (error, res) => {
113
+ t.error(error)
114
+ t.equal(res.statusCode, 418)
115
+ t.same(JSON.parse(res.payload), {
116
+ message: 'Make a brew',
117
+ statusCode: 418,
118
+ error: 'Wrong Pot Error'
119
+ })
120
+ })
121
+ })
122
+
123
+ test('route error handler does not affect other routes', t => {
124
+ t.plan(3)
125
+
126
+ const fastify = Fastify()
127
+
128
+ const customRouteErrorHandler = (error, request, reply) => {
129
+ t.equal(error.message, 'Wrong Pot Error')
130
+
131
+ reply.code(418).send({
132
+ message: 'Make a brew',
133
+ statusCode: 418,
134
+ error: 'Wrong Pot Error'
135
+ })
136
+ }
137
+
138
+ fastify.route({
139
+ method: 'GET',
140
+ path: '/coffee',
141
+ handler: (req, res) => {
142
+ res.send(new Error('Wrong Pot Error'))
143
+ },
144
+ errorHandler: customRouteErrorHandler
145
+ })
146
+
147
+ fastify.route({
148
+ method: 'GET',
149
+ path: '/tea',
150
+ handler: (req, res) => {
151
+ res.send(new Error('No tea today'))
152
+ }
153
+ })
154
+
155
+ fastify.inject({
156
+ method: 'GET',
157
+ url: '/tea'
158
+ }, (error, res) => {
159
+ t.error(error)
160
+ t.equal(res.statusCode, 500)
161
+ t.same(JSON.parse(res.payload), {
162
+ message: 'No tea today',
163
+ statusCode: 500,
164
+ error: 'Internal Server Error'
165
+ })
166
+ })
167
+ })
168
+
169
+ test('async error handler for a route', t => {
170
+ t.plan(4)
171
+
172
+ const fastify = Fastify()
173
+
174
+ const customRouteErrorHandler = async (error, request, reply) => {
175
+ t.equal(error.message, 'Delayed Pot Error')
176
+ reply.code(418)
177
+ return {
178
+ message: 'Make a brew sometime later',
179
+ statusCode: 418,
180
+ error: 'Delayed Pot Error'
181
+ }
182
+ }
183
+
184
+ fastify.route({
185
+ method: 'GET',
186
+ path: '/late-coffee',
187
+ handler: (req, res) => {
188
+ res.send(new Error('Delayed Pot Error'))
189
+ },
190
+ errorHandler: customRouteErrorHandler
191
+ })
192
+
193
+ fastify.inject({
194
+ method: 'GET',
195
+ url: '/late-coffee'
196
+ }, (error, res) => {
197
+ t.error(error)
198
+ t.equal(res.statusCode, 418)
199
+ t.same(JSON.parse(res.payload), {
200
+ message: 'Make a brew sometime later',
201
+ statusCode: 418,
202
+ error: 'Delayed Pot Error'
203
+ })
204
+ })
205
+ })