fastify 2.4.1 → 2.7.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 (51) hide show
  1. package/README.md +1 -1
  2. package/SECURITY.md +33 -0
  3. package/build/build-validation.js +1 -1
  4. package/docs/Decorators.md +2 -2
  5. package/docs/Ecosystem.md +5 -1
  6. package/docs/Fluent-Schema.md +5 -7
  7. package/docs/Hooks.md +40 -40
  8. package/docs/Logging.md +15 -3
  9. package/docs/Plugins-Guide.md +21 -21
  10. package/docs/Plugins.md +11 -11
  11. package/docs/Reply.md +14 -7
  12. package/docs/Routes.md +6 -6
  13. package/docs/Server.md +40 -19
  14. package/docs/Serverless.md +127 -28
  15. package/docs/Validation-and-Serialization.md +15 -12
  16. package/fastify.d.ts +22 -14
  17. package/fastify.js +21 -0
  18. package/lib/context.js +5 -4
  19. package/lib/decorate.js +2 -0
  20. package/lib/errors.js +1 -0
  21. package/lib/handleRequest.js +2 -2
  22. package/lib/reply.js +23 -6
  23. package/lib/request.js +2 -2
  24. package/lib/route.js +24 -15
  25. package/lib/schemas.js +24 -3
  26. package/lib/symbols.js +1 -0
  27. package/lib/validation.js +19 -0
  28. package/package.json +19 -18
  29. package/test/async-await.js +1 -1
  30. package/test/close-pipelining.test.js +43 -2
  31. package/test/close.test.js +69 -12
  32. package/test/content-length.test.js +2 -2
  33. package/test/decorator.test.js +2 -0
  34. package/test/fluent-schema.js +54 -0
  35. package/test/hooks-async.js +80 -1
  36. package/test/hooks.test.js +4 -4
  37. package/test/http2/closing.js +86 -33
  38. package/test/input-validation.test.js +1 -1
  39. package/test/internals/decorator.test.js +2 -0
  40. package/test/internals/initialConfig.test.js +1 -1
  41. package/test/internals/reply.test.js +276 -1
  42. package/test/internals/validation.test.js +57 -0
  43. package/test/logger.test.js +33 -1
  44. package/test/nullable-validation.test.js +52 -0
  45. package/test/plugin.test.js +2 -0
  46. package/test/register.test.js +2 -0
  47. package/test/route-prefix.test.js +31 -0
  48. package/test/route.test.js +35 -0
  49. package/test/shared-schemas.test.js +3 -3
  50. package/test/types/index.ts +33 -2
  51. package/test/versioned-routes.test.js +3 -3
@@ -120,6 +120,60 @@ function fluentSchemaTest (t) {
120
120
 
121
121
  fastify.ready(t.error)
122
122
  })
123
+
124
+ test('Should call valueOf internally', t => {
125
+ t.plan(1)
126
+
127
+ const fastify = new Fastify()
128
+
129
+ const addressSchema = S.object()
130
+ .id('#address')
131
+ .prop('line1').required()
132
+ .prop('line2')
133
+ .prop('country').required()
134
+ .prop('city').required()
135
+ .prop('zipcode').required()
136
+
137
+ const commonSchemas = S.object()
138
+ .id('https://fastify/demo')
139
+ .definition('addressSchema', addressSchema)
140
+
141
+ fastify.addSchema(commonSchemas)
142
+
143
+ fastify.route({
144
+ method: 'POST',
145
+ url: '/query',
146
+ handler: () => {},
147
+ schema: {
148
+ query: S.object().prop('hello', S.string()).required(),
149
+ body: S.object().prop('hello', S.string()).required(),
150
+ params: S.object().prop('hello', S.string()).required(),
151
+ headers: S.object().prop('hello', S.string()).required(),
152
+ response: {
153
+ 200: S.object().prop('hello', S.string()).required(),
154
+ 201: S.object().prop('hello', S.string()).required()
155
+ }
156
+ }
157
+ })
158
+
159
+ fastify.route({
160
+ method: 'POST',
161
+ url: '/querystring',
162
+ handler: () => {},
163
+ schema: {
164
+ querystring: S.object().prop('hello', S.string()).required(),
165
+ body: S.object().prop('hello', S.string()).required(),
166
+ params: S.object().prop('hello', S.string()).required(),
167
+ headers: S.object().prop('hello', S.string()).required(),
168
+ response: {
169
+ 200: S.object().prop('hello', S.string()).required(),
170
+ 201: S.object().prop('hello', S.string()).required()
171
+ }
172
+ }
173
+ })
174
+
175
+ fastify.ready(t.error)
176
+ })
123
177
  }
124
178
 
125
179
  module.exports = fluentSchemaTest
@@ -4,7 +4,8 @@ const split = require('split2')
4
4
  const sget = require('simple-get').concat
5
5
  const Fastify = require('..')
6
6
  const fs = require('fs')
7
- const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
7
+ const { promisify } = require('util')
8
+ const sleep = promisify(setTimeout)
8
9
 
9
10
  function asyncHookTest (t) {
10
11
  const test = t.test
@@ -231,6 +232,53 @@ function asyncHookTest (t) {
231
232
  })
232
233
  })
233
234
 
235
+ test('preValidation hooks should be able to block a request with async onSend', t => {
236
+ t.plan(5)
237
+ const fastify = Fastify()
238
+
239
+ fastify.addHook('preValidation', async (req, reply) => {
240
+ reply.send('hello')
241
+ })
242
+
243
+ fastify.addHook('onSend', async (req, reply, payload) => {
244
+ await sleep(10)
245
+ t.equal(payload, 'hello')
246
+ })
247
+
248
+ fastify.addHook('preHandler', async (request, reply) => {
249
+ t.fail('we should not be here')
250
+ })
251
+
252
+ fastify.addHook('onResponse', async (request, reply) => {
253
+ t.ok('called')
254
+ })
255
+
256
+ fastify.post('/', {
257
+ schema: {
258
+ body: {
259
+ type: 'object',
260
+ properties: {
261
+ hello: {
262
+ type: 'string'
263
+ }
264
+ },
265
+ required: ['hello']
266
+ }
267
+ }
268
+ }, function (request, reply) {
269
+ t.fail('we should not be here')
270
+ })
271
+
272
+ fastify.inject({
273
+ url: '/',
274
+ method: 'POST'
275
+ }, (err, res) => {
276
+ t.error(err)
277
+ t.is(res.statusCode, 200)
278
+ t.is(res.payload, 'hello')
279
+ })
280
+ })
281
+
234
282
  test('preSerialization hooks should be able to modify the payload', t => {
235
283
  t.plan(3)
236
284
  const fastify = Fastify()
@@ -339,6 +387,37 @@ function asyncHookTest (t) {
339
387
  })
340
388
  })
341
389
 
390
+ test('preHandler hooks should be able to block a request (last hook) with a delay in onSend', t => {
391
+ t.plan(5)
392
+ const fastify = Fastify()
393
+
394
+ fastify.addHook('preHandler', async (req, reply) => {
395
+ reply.send('hello')
396
+ })
397
+
398
+ fastify.addHook('onSend', async (req, reply, payload) => {
399
+ await sleep(10)
400
+ t.equal(payload, 'hello')
401
+ })
402
+
403
+ fastify.addHook('onResponse', async (request, reply) => {
404
+ t.ok('called')
405
+ })
406
+
407
+ fastify.get('/', function (request, reply) {
408
+ t.fail('we should not be here')
409
+ })
410
+
411
+ fastify.inject({
412
+ url: '/',
413
+ method: 'GET'
414
+ }, (err, res) => {
415
+ t.error(err)
416
+ t.is(res.statusCode, 200)
417
+ t.is(res.payload, 'hello')
418
+ })
419
+ })
420
+
342
421
  test('onRequest respond with a stream', t => {
343
422
  t.plan(4)
344
423
  const fastify = Fastify()
@@ -1935,7 +1935,7 @@ test('request in onRequest, preParsing, preValidation and onResponse', t => {
1935
1935
  t.deepEqual(request.headers, {
1936
1936
  'content-length': '17',
1937
1937
  'content-type': 'application/json',
1938
- 'host': 'localhost:80',
1938
+ host: 'localhost:80',
1939
1939
  'user-agent': 'lightMyRequest',
1940
1940
  'x-custom': 'hello'
1941
1941
  })
@@ -1949,7 +1949,7 @@ test('request in onRequest, preParsing, preValidation and onResponse', t => {
1949
1949
  t.deepEqual(request.headers, {
1950
1950
  'content-length': '17',
1951
1951
  'content-type': 'application/json',
1952
- 'host': 'localhost:80',
1952
+ host: 'localhost:80',
1953
1953
  'user-agent': 'lightMyRequest',
1954
1954
  'x-custom': 'hello'
1955
1955
  })
@@ -1963,7 +1963,7 @@ test('request in onRequest, preParsing, preValidation and onResponse', t => {
1963
1963
  t.deepEqual(request.headers, {
1964
1964
  'content-length': '17',
1965
1965
  'content-type': 'application/json',
1966
- 'host': 'localhost:80',
1966
+ host: 'localhost:80',
1967
1967
  'user-agent': 'lightMyRequest',
1968
1968
  'x-custom': 'hello'
1969
1969
  })
@@ -1977,7 +1977,7 @@ test('request in onRequest, preParsing, preValidation and onResponse', t => {
1977
1977
  t.deepEqual(request.headers, {
1978
1978
  'content-length': '17',
1979
1979
  'content-type': 'application/json',
1980
- 'host': 'localhost:80',
1980
+ host: 'localhost:80',
1981
1981
  'user-agent': 'lightMyRequest',
1982
1982
  'x-custom': 'hello'
1983
1983
  })
@@ -1,48 +1,101 @@
1
1
  'use strict'
2
2
 
3
3
  const t = require('tap')
4
- const test = t.test
5
4
  const Fastify = require('../..')
6
5
  const http2 = require('http2')
7
6
  const semver = require('semver')
8
7
 
9
- let fastify
10
- try {
11
- fastify = Fastify({
12
- http2: true
13
- })
14
- t.pass('http2 successfully loaded')
15
- } catch (e) {
16
- t.fail('http2 loading failed', e)
17
- }
18
-
19
- fastify.listen(0, err => {
20
- t.error(err)
21
- fastify.server.unref()
22
-
23
- // Skipped because there is likely a bug on Node 8.
24
- test('http/2 request while fastify closing', { skip: semver.lt(process.versions.node, '10.15.0') }, t => {
25
- const url = `http://127.0.0.1:${fastify.server.address().port}`
26
- const session = http2.connect(url, function () {
27
- this.request({
28
- ':method': 'GET',
29
- ':path': '/'
30
- }).on('response', headers => {
31
- t.strictEqual(headers[':status'], 503)
32
- t.end()
33
- this.destroy()
34
- }).on('error', () => {
8
+ t.test('http/2 request while fastify closing', t => {
9
+ let fastify
10
+ try {
11
+ fastify = Fastify({
12
+ http2: true
13
+ })
14
+ t.pass('http2 successfully loaded')
15
+ } catch (e) {
16
+ t.fail('http2 loading failed', e)
17
+ }
18
+
19
+ fastify.get('/', () => Promise.resolve({}))
20
+
21
+ fastify.listen(0, err => {
22
+ t.error(err)
23
+ fastify.server.unref()
24
+
25
+ // Skipped because there is likely a bug on Node 8.
26
+ t.test('return 200', { skip: semver.lt(process.versions.node, '10.15.0') }, t => {
27
+ const url = `http://127.0.0.1:${fastify.server.address().port}`
28
+ const session = http2.connect(url, function () {
29
+ this.request({
30
+ ':method': 'GET',
31
+ ':path': '/'
32
+ }).on('response', headers => {
33
+ t.strictEqual(headers[':status'], 503)
34
+ t.end()
35
+ this.destroy()
36
+ }).on('error', () => {
37
+ // Nothing to do here,
38
+ // we are not interested in this error that might
39
+ // happen or not
40
+ })
41
+ fastify.close()
42
+ })
43
+ session.on('error', () => {
35
44
  // Nothing to do here,
36
45
  // we are not interested in this error that might
37
46
  // happen or not
47
+ t.end()
38
48
  })
39
- fastify.close()
40
49
  })
41
- session.on('error', () => {
42
- // Nothing to do here,
43
- // we are not interested in this error that might
44
- // happen or not
45
- t.end()
50
+
51
+ t.end()
52
+ })
53
+ })
54
+
55
+ t.test('http/2 request while fastify closing - return503OnClosing: false', t => {
56
+ let fastify
57
+ try {
58
+ fastify = Fastify({
59
+ http2: true,
60
+ return503OnClosing: false
46
61
  })
62
+ t.pass('http2 successfully loaded')
63
+ } catch (e) {
64
+ t.fail('http2 loading failed', e)
65
+ }
66
+
67
+ fastify.get('/', () => Promise.resolve({}))
68
+
69
+ fastify.listen(0, err => {
70
+ t.error(err)
71
+ fastify.server.unref()
72
+
73
+ // Skipped because there is likely a bug on Node 8.
74
+ t.test('return 200', { skip: semver.lt(process.versions.node, '10.15.0') }, t => {
75
+ const url = `http://127.0.0.1:${fastify.server.address().port}`
76
+ const session = http2.connect(url, function () {
77
+ this.request({
78
+ ':method': 'GET',
79
+ ':path': '/'
80
+ }).on('response', headers => {
81
+ t.strictEqual(headers[':status'], 200)
82
+ t.end()
83
+ this.destroy()
84
+ }).on('error', () => {
85
+ // Nothing to do here,
86
+ // we are not interested in this error that might
87
+ // happen or not
88
+ })
89
+ fastify.close()
90
+ })
91
+ session.on('error', () => {
92
+ // Nothing to do here,
93
+ // we are not interested in this error that might
94
+ // happen or not
95
+ t.end()
96
+ })
97
+ })
98
+
99
+ t.end()
47
100
  })
48
101
  })
@@ -27,7 +27,7 @@ test('case insensitive header validation', t => {
27
27
  method: 'GET',
28
28
  url: '/',
29
29
  headers: {
30
- 'FooBar': 'Baz'
30
+ FooBar: 'Baz'
31
31
  }
32
32
  }, (err, res) => {
33
33
  t.error(err)
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ /* eslint no-prototype-builtins: 0 */
4
+
3
5
  const t = require('tap')
4
6
  const test = t.test
5
7
  const decorator = require('../../lib/decorate')
@@ -59,7 +59,7 @@ test('Fastify.initialConfig should expose all options', t => {
59
59
  }
60
60
  }
61
61
 
62
- let options = {
62
+ const options = {
63
63
  http2: true,
64
64
  https: {
65
65
  key: fs.readFileSync(path.join(__dirname, '..', 'https', 'fastify.key')),
@@ -14,7 +14,7 @@ const {
14
14
  } = require('../../lib/symbols')
15
15
 
16
16
  test('Once called, Reply should return an object with methods', t => {
17
- t.plan(12)
17
+ t.plan(13)
18
18
  const response = { res: 'res' }
19
19
  function context () {}
20
20
  function request () {}
@@ -27,6 +27,7 @@ test('Once called, Reply should return an object with methods', t => {
27
27
  t.is(typeof reply.status, 'function')
28
28
  t.is(typeof reply.header, 'function')
29
29
  t.is(typeof reply.serialize, 'function')
30
+ t.is(typeof reply.getResponseTime, 'function')
30
31
  t.is(typeof reply[kReplyHeaders], 'object')
31
32
  t.strictEqual(reply.res, response)
32
33
  t.strictEqual(reply.context, context)
@@ -977,3 +978,277 @@ test('should throw error when attempting to set reply.sent more than once', t =>
977
978
  t.pass()
978
979
  })
979
980
  })
981
+
982
+ test('reply.getResponseTime() should return 0 before the timer is initialised on the reply by setting up response listeners', t => {
983
+ t.plan(1)
984
+ const response = { statusCode: 200 }
985
+ const context = {}
986
+ const reply = new Reply(response, context, null)
987
+ t.equal(reply.getResponseTime(), 0)
988
+ })
989
+
990
+ test('reply.getResponseTime() should return a number greater than 0 after the timer is initialised on the reply by setting up response listeners', t => {
991
+ t.plan(1)
992
+ const fastify = require('../..')()
993
+ fastify.route({
994
+ method: 'GET',
995
+ url: '/',
996
+ handler: (req, reply) => {
997
+ reply.send('hello world')
998
+ }
999
+ })
1000
+
1001
+ fastify.addHook('onResponse', (req, reply) => {
1002
+ t.true(reply.getResponseTime() > 0)
1003
+ t.end()
1004
+ })
1005
+
1006
+ fastify.inject({ method: 'GET', url: '/' })
1007
+ })
1008
+
1009
+ test('reply should use the custom serializer', t => {
1010
+ t.plan(4)
1011
+ const fastify = require('../..')()
1012
+ fastify.setReplySerializer((payload, statusCode) => {
1013
+ t.deepEqual(payload, { foo: 'bar' })
1014
+ t.equal(statusCode, 200)
1015
+ payload.foo = 'bar bar'
1016
+ return JSON.stringify(payload)
1017
+ })
1018
+
1019
+ fastify.route({
1020
+ method: 'GET',
1021
+ url: '/',
1022
+ handler: (req, reply) => {
1023
+ reply.send({ foo: 'bar' })
1024
+ }
1025
+ })
1026
+
1027
+ fastify.inject({
1028
+ method: 'GET',
1029
+ url: '/'
1030
+ }, (err, res) => {
1031
+ t.error(err)
1032
+ t.strictEqual(res.payload, '{"foo":"bar bar"}')
1033
+ })
1034
+ })
1035
+
1036
+ test('reply should use the right serializer in encapsulated context', t => {
1037
+ t.plan(9)
1038
+
1039
+ const fastify = require('../..')()
1040
+ fastify.setReplySerializer((payload) => {
1041
+ t.deepEqual(payload, { foo: 'bar' })
1042
+ payload.foo = 'bar bar'
1043
+ return JSON.stringify(payload)
1044
+ })
1045
+
1046
+ fastify.route({
1047
+ method: 'GET',
1048
+ url: '/',
1049
+ handler: (req, reply) => { reply.send({ foo: 'bar' }) }
1050
+ })
1051
+
1052
+ fastify.register(function (instance, opts, next) {
1053
+ instance.route({
1054
+ method: 'GET',
1055
+ url: '/sub',
1056
+ handler: (req, reply) => { reply.send({ john: 'doo' }) }
1057
+ })
1058
+ instance.setReplySerializer((payload) => {
1059
+ t.deepEqual(payload, { john: 'doo' })
1060
+ payload.john = 'too too'
1061
+ return JSON.stringify(payload)
1062
+ })
1063
+ next()
1064
+ })
1065
+
1066
+ fastify.register(function (instance, opts, next) {
1067
+ instance.route({
1068
+ method: 'GET',
1069
+ url: '/sub',
1070
+ handler: (req, reply) => { reply.send({ sweet: 'potato' }) }
1071
+ })
1072
+ instance.setReplySerializer((payload) => {
1073
+ t.deepEqual(payload, { sweet: 'potato' })
1074
+ payload.sweet = 'potato potato'
1075
+ return JSON.stringify(payload)
1076
+ })
1077
+ next()
1078
+ }, { prefix: 'sub' })
1079
+
1080
+ fastify.inject({
1081
+ method: 'GET',
1082
+ url: '/'
1083
+ }, (err, res) => {
1084
+ t.error(err)
1085
+ t.strictEqual(res.payload, '{"foo":"bar bar"}')
1086
+ })
1087
+
1088
+ fastify.inject({
1089
+ method: 'GET',
1090
+ url: '/sub'
1091
+ }, (err, res) => {
1092
+ t.error(err)
1093
+ t.strictEqual(res.payload, '{"john":"too too"}')
1094
+ })
1095
+
1096
+ fastify.inject({
1097
+ method: 'GET',
1098
+ url: '/sub/sub'
1099
+ }, (err, res) => {
1100
+ t.error(err)
1101
+ t.strictEqual(res.payload, '{"sweet":"potato potato"}')
1102
+ })
1103
+ })
1104
+
1105
+ test('reply should use the right serializer in deep encapsulated context', t => {
1106
+ t.plan(8)
1107
+
1108
+ const fastify = require('../..')()
1109
+
1110
+ fastify.route({
1111
+ method: 'GET',
1112
+ url: '/',
1113
+ handler: (req, reply) => { reply.send({ foo: 'bar' }) }
1114
+ })
1115
+
1116
+ fastify.register(function (instance, opts, next) {
1117
+ instance.route({
1118
+ method: 'GET',
1119
+ url: '/sub',
1120
+ handler: (req, reply) => { reply.send({ john: 'doo' }) }
1121
+ })
1122
+ instance.setReplySerializer((payload) => {
1123
+ t.deepEqual(payload, { john: 'doo' })
1124
+ payload.john = 'too too'
1125
+ return JSON.stringify(payload)
1126
+ })
1127
+
1128
+ instance.register(function (subInstance, opts, next) {
1129
+ subInstance.route({
1130
+ method: 'GET',
1131
+ url: '/deep',
1132
+ handler: (req, reply) => { reply.send({ john: 'deep' }) }
1133
+ })
1134
+ subInstance.setReplySerializer((payload) => {
1135
+ t.deepEqual(payload, { john: 'deep' })
1136
+ payload.john = 'deep deep'
1137
+ return JSON.stringify(payload)
1138
+ })
1139
+ next()
1140
+ })
1141
+ next()
1142
+ })
1143
+
1144
+ fastify.inject({
1145
+ method: 'GET',
1146
+ url: '/'
1147
+ }, (err, res) => {
1148
+ t.error(err)
1149
+ t.strictEqual(res.payload, '{"foo":"bar"}')
1150
+ })
1151
+
1152
+ fastify.inject({
1153
+ method: 'GET',
1154
+ url: '/sub'
1155
+ }, (err, res) => {
1156
+ t.error(err)
1157
+ t.strictEqual(res.payload, '{"john":"too too"}')
1158
+ })
1159
+
1160
+ fastify.inject({
1161
+ method: 'GET',
1162
+ url: '/deep'
1163
+ }, (err, res) => {
1164
+ t.error(err)
1165
+ t.strictEqual(res.payload, '{"john":"deep deep"}')
1166
+ })
1167
+ })
1168
+
1169
+ test('reply should use the route serializer', t => {
1170
+ t.plan(3)
1171
+
1172
+ const fastify = require('../..')()
1173
+ fastify.setReplySerializer(() => {
1174
+ t.fail('this serializer should not be executed')
1175
+ })
1176
+
1177
+ fastify.route({
1178
+ method: 'GET',
1179
+ url: '/',
1180
+ handler: (req, reply) => {
1181
+ reply
1182
+ .serializer((payload) => {
1183
+ t.deepEqual(payload, { john: 'doo' })
1184
+ payload.john = 'too too'
1185
+ return JSON.stringify(payload)
1186
+ })
1187
+ .send({ john: 'doo' })
1188
+ }
1189
+ })
1190
+
1191
+ fastify.inject({
1192
+ method: 'GET',
1193
+ url: '/'
1194
+ }, (err, res) => {
1195
+ t.error(err)
1196
+ t.strictEqual(res.payload, '{"john":"too too"}')
1197
+ })
1198
+ })
1199
+
1200
+ test('cannot set the replySerializer when the server is running', t => {
1201
+ t.plan(2)
1202
+
1203
+ const fastify = require('../..')()
1204
+ t.teardown(fastify.close.bind(fastify))
1205
+
1206
+ fastify.listen(err => {
1207
+ t.error(err)
1208
+ try {
1209
+ fastify.setReplySerializer(() => {})
1210
+ t.fail('this serializer should not be setup')
1211
+ } catch (e) {
1212
+ t.is(e.message, 'Cannot call "setReplySerializer" when fastify instance is already started!')
1213
+ }
1214
+ })
1215
+ })
1216
+
1217
+ test('reply should not call the custom serializer for errors and not found', t => {
1218
+ t.plan(9)
1219
+
1220
+ const fastify = require('../..')()
1221
+ fastify.setReplySerializer((payload, statusCode) => {
1222
+ t.deepEqual(payload, { foo: 'bar' })
1223
+ t.equal(statusCode, 200)
1224
+ return JSON.stringify(payload)
1225
+ })
1226
+
1227
+ fastify.get('/', (req, reply) => { reply.send({ foo: 'bar' }) })
1228
+ fastify.get('/err', (req, reply) => { reply.send(new Error('an error')) })
1229
+
1230
+ fastify.inject({
1231
+ method: 'GET',
1232
+ url: '/'
1233
+ }, (err, res) => {
1234
+ t.error(err)
1235
+ t.strictEqual(res.statusCode, 200)
1236
+ t.strictEqual(res.payload, '{"foo":"bar"}')
1237
+ })
1238
+
1239
+ fastify.inject({
1240
+ method: 'GET',
1241
+ url: '/err'
1242
+ }, (err, res) => {
1243
+ t.error(err)
1244
+ t.strictEqual(res.statusCode, 500)
1245
+ })
1246
+
1247
+ fastify.inject({
1248
+ method: 'GET',
1249
+ url: '/not-existing'
1250
+ }, (err, res) => {
1251
+ t.error(err)
1252
+ t.strictEqual(res.statusCode, 404)
1253
+ })
1254
+ })