fastify 4.6.0 → 4.8.0

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 (48) hide show
  1. package/docs/Guides/Ecosystem.md +20 -9
  2. package/docs/Guides/Plugins-Guide.md +44 -0
  3. package/docs/Guides/Testing.md +50 -17
  4. package/docs/Reference/Errors.md +205 -60
  5. package/docs/Reference/Hooks.md +27 -0
  6. package/docs/Reference/Reply.md +5 -5
  7. package/docs/Reference/Request.md +19 -6
  8. package/docs/Reference/Routes.md +56 -2
  9. package/docs/Reference/Server.md +3 -0
  10. package/docs/Reference/Type-Providers.md +3 -3
  11. package/fastify.d.ts +6 -0
  12. package/fastify.js +58 -25
  13. package/lib/contentTypeParser.js +10 -9
  14. package/lib/context.js +27 -3
  15. package/lib/error-handler.js +7 -3
  16. package/lib/errors.js +39 -28
  17. package/lib/handleRequest.js +15 -13
  18. package/lib/reply.js +42 -34
  19. package/lib/request.js +36 -18
  20. package/lib/route.js +22 -11
  21. package/lib/schema-controller.js +7 -1
  22. package/lib/server.js +2 -2
  23. package/lib/symbols.js +2 -0
  24. package/lib/validation.js +4 -3
  25. package/lib/warnings.js +2 -0
  26. package/package.json +26 -26
  27. package/test/404s.test.js +19 -1
  28. package/test/constrained-routes.test.js +114 -0
  29. package/test/context-config.test.js +2 -1
  30. package/test/handler-context.test.js +12 -30
  31. package/test/internals/contentTypeParser.test.js +3 -3
  32. package/test/internals/handleRequest.test.js +4 -3
  33. package/test/internals/reply-serialize.test.js +9 -9
  34. package/test/internals/reply.test.js +10 -9
  35. package/test/internals/request-validate.test.js +97 -9
  36. package/test/internals/request.test.js +57 -3
  37. package/test/internals/validation.test.js +15 -0
  38. package/test/plugin.test.js +1 -1
  39. package/test/reply-code.test.js +59 -0
  40. package/test/route.test.js +29 -0
  41. package/test/router-options.test.js +89 -68
  42. package/test/schema-feature.test.js +25 -0
  43. package/test/schema-validation.test.js +19 -0
  44. package/test/search.test.js +169 -30
  45. package/test/server.test.js +54 -0
  46. package/test/types/fastify.test-d.ts +5 -1
  47. package/types/errors.d.ts +53 -0
  48. package/types/request.d.ts +9 -3
@@ -268,6 +268,21 @@ test('build schema - headers are not lowercased in case of custom object', t =>
268
268
  })
269
269
  })
270
270
 
271
+ test('build schema - headers are not lowercased in case of custom validator provided', t => {
272
+ t.plan(1)
273
+
274
+ class Headers {}
275
+ const opts = {
276
+ schema: {
277
+ headers: new Headers()
278
+ }
279
+ }
280
+ validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => {
281
+ t.type(schema, Headers)
282
+ return () => {}
283
+ }, true)
284
+ })
285
+
271
286
  test('build schema - uppercased headers are not included', t => {
272
287
  t.plan(1)
273
288
  const opts = {
@@ -885,7 +885,7 @@ test('pluginTimeout', t => {
885
885
  })
886
886
  })
887
887
 
888
- test('pluginTimeout - named function', { only: true }, t => {
888
+ test('pluginTimeout - named function', t => {
889
889
  t.plan(5)
890
890
  const fastify = Fastify({
891
891
  pluginTimeout: 10
@@ -0,0 +1,59 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const test = t.test
5
+ const Fastify = require('..')
6
+
7
+ test('code should handle null/undefined/float', t => {
8
+ t.plan(8)
9
+
10
+ const fastify = Fastify()
11
+
12
+ fastify.get('/null', function (request, reply) {
13
+ reply.status(null).send()
14
+ })
15
+
16
+ fastify.get('/undefined', function (request, reply) {
17
+ reply.status(undefined).send()
18
+ })
19
+
20
+ fastify.get('/404.5', function (request, reply) {
21
+ reply.status(404.5).send()
22
+ })
23
+
24
+ fastify.inject({
25
+ method: 'GET',
26
+ url: '/null'
27
+ }, (error, res) => {
28
+ t.error(error)
29
+ t.equal(res.statusCode, 500)
30
+ t.same(res.json(), {
31
+ statusCode: 500,
32
+ code: 'FST_ERR_BAD_STATUS_CODE',
33
+ error: 'Internal Server Error',
34
+ message: 'Called reply with an invalid status code: null'
35
+ })
36
+ })
37
+
38
+ fastify.inject({
39
+ method: 'GET',
40
+ url: '/undefined'
41
+ }, (error, res) => {
42
+ t.error(error)
43
+ t.equal(res.statusCode, 500)
44
+ t.same(res.json(), {
45
+ statusCode: 500,
46
+ code: 'FST_ERR_BAD_STATUS_CODE',
47
+ error: 'Internal Server Error',
48
+ message: 'Called reply with an invalid status code: undefined'
49
+ })
50
+ })
51
+
52
+ fastify.inject({
53
+ method: 'GET',
54
+ url: '/404.5'
55
+ }, (error, res) => {
56
+ t.error(error)
57
+ t.equal(res.statusCode, 404)
58
+ })
59
+ })
@@ -1464,3 +1464,32 @@ test('invalid url attribute - non string URL', t => {
1464
1464
  t.equal(error.code, FST_ERR_INVALID_URL().code)
1465
1465
  }
1466
1466
  })
1467
+
1468
+ test('exposeHeadRoute should not reuse the same route option', async t => {
1469
+ t.plan(2)
1470
+
1471
+ const fastify = Fastify()
1472
+
1473
+ // we update the onRequest hook in onRoute hook
1474
+ // if we reuse the same route option
1475
+ // that means we will append another function inside the array
1476
+ fastify.addHook('onRoute', function (routeOption) {
1477
+ if (Array.isArray(routeOption.onRequest)) {
1478
+ routeOption.onRequest.push(() => {})
1479
+ } else {
1480
+ routeOption.onRequest = [() => {}]
1481
+ }
1482
+ })
1483
+
1484
+ fastify.addHook('onRoute', function (routeOption) {
1485
+ t.equal(routeOption.onRequest.length, 1)
1486
+ })
1487
+
1488
+ fastify.route({
1489
+ method: 'GET',
1490
+ path: '/more-coffee',
1491
+ async handler () {
1492
+ return 'hello world'
1493
+ }
1494
+ })
1495
+ })
@@ -1,20 +1,13 @@
1
1
  'use strict'
2
2
 
3
3
  const test = require('tap').test
4
- const sget = require('simple-get')
5
4
  const Fastify = require('../')
6
- const { FST_ERR_BAD_URL } = require('../lib/errors')
7
-
8
- function getUrl (app) {
9
- const { address, port } = app.server.address()
10
- if (address === '::1') {
11
- return `http://[${address}]:${port}`
12
- } else {
13
- return `http://${address}:${port}`
14
- }
15
- }
5
+ const {
6
+ FST_ERR_BAD_URL,
7
+ FST_ERR_ASYNC_CONSTRAINT
8
+ } = require('../lib/errors')
16
9
 
17
- test('Should honor ignoreTrailingSlash option', t => {
10
+ test('Should honor ignoreTrailingSlash option', async t => {
18
11
  t.plan(4)
19
12
  const fastify = Fastify({
20
13
  ignoreTrailingSlash: true
@@ -24,27 +17,16 @@ test('Should honor ignoreTrailingSlash option', t => {
24
17
  res.send('test')
25
18
  })
26
19
 
27
- fastify.listen({ port: 0 }, (err) => {
28
- t.teardown(() => { fastify.close() })
29
- if (err) t.threw(err)
30
-
31
- const baseUrl = getUrl(fastify)
32
-
33
- sget.concat(baseUrl + '/test', (err, res, data) => {
34
- if (err) t.threw(err)
35
- t.equal(res.statusCode, 200)
36
- t.equal(data.toString(), 'test')
37
- })
20
+ let res = await fastify.inject('/test')
21
+ t.equal(res.statusCode, 200)
22
+ t.equal(res.payload.toString(), 'test')
38
23
 
39
- sget.concat(baseUrl + '/test/', (err, res, data) => {
40
- if (err) t.threw(err)
41
- t.equal(res.statusCode, 200)
42
- t.equal(data.toString(), 'test')
43
- })
44
- })
24
+ res = await fastify.inject('/test/')
25
+ t.equal(res.statusCode, 200)
26
+ t.equal(res.payload.toString(), 'test')
45
27
  })
46
28
 
47
- test('Should honor ignoreDuplicateSlashes option', t => {
29
+ test('Should honor ignoreDuplicateSlashes option', async t => {
48
30
  t.plan(4)
49
31
  const fastify = Fastify({
50
32
  ignoreDuplicateSlashes: true
@@ -54,27 +36,16 @@ test('Should honor ignoreDuplicateSlashes option', t => {
54
36
  res.send('test')
55
37
  })
56
38
 
57
- fastify.listen({ port: 0 }, (err) => {
58
- t.teardown(() => { fastify.close() })
59
- if (err) t.threw(err)
60
-
61
- const baseUrl = getUrl(fastify)
62
-
63
- sget.concat(baseUrl + '/test/test/test', (err, res, data) => {
64
- if (err) t.threw(err)
65
- t.equal(res.statusCode, 200)
66
- t.equal(data.toString(), 'test')
67
- })
39
+ let res = await fastify.inject('/test/test/test')
40
+ t.equal(res.statusCode, 200)
41
+ t.equal(res.payload.toString(), 'test')
68
42
 
69
- sget.concat(baseUrl + '/test//test///test', (err, res, data) => {
70
- if (err) t.threw(err)
71
- t.equal(res.statusCode, 200)
72
- t.equal(data.toString(), 'test')
73
- })
74
- })
43
+ res = await fastify.inject('/test//test///test')
44
+ t.equal(res.statusCode, 200)
45
+ t.equal(res.payload.toString(), 'test')
75
46
  })
76
47
 
77
- test('Should honor ignoreTrailingSlash and ignoreDuplicateSlashes options', t => {
48
+ test('Should honor ignoreTrailingSlash and ignoreDuplicateSlashes options', async t => {
78
49
  t.plan(4)
79
50
  const fastify = Fastify({
80
51
  ignoreTrailingSlash: true,
@@ -85,24 +56,13 @@ test('Should honor ignoreTrailingSlash and ignoreDuplicateSlashes options', t =>
85
56
  res.send('test')
86
57
  })
87
58
 
88
- fastify.listen({ port: 0 }, (err) => {
89
- t.teardown(() => { fastify.close() })
90
- if (err) t.threw(err)
91
-
92
- const baseUrl = getUrl(fastify)
93
-
94
- sget.concat(baseUrl + '/test/test/test/', (err, res, data) => {
95
- if (err) t.threw(err)
96
- t.equal(res.statusCode, 200)
97
- t.equal(data.toString(), 'test')
98
- })
59
+ let res = await fastify.inject('/test/test/test/')
60
+ t.equal(res.statusCode, 200)
61
+ t.equal(res.payload.toString(), 'test')
99
62
 
100
- sget.concat(baseUrl + '/test//test///test//', (err, res, data) => {
101
- if (err) t.threw(err)
102
- t.equal(res.statusCode, 200)
103
- t.equal(data.toString(), 'test')
104
- })
105
- })
63
+ res = await fastify.inject('/test//test///test//')
64
+ t.equal(res.statusCode, 200)
65
+ t.equal(res.payload.toString(), 'test')
106
66
  })
107
67
 
108
68
  test('Should honor maxParamLength option', t => {
@@ -131,12 +91,22 @@ test('Should honor maxParamLength option', t => {
131
91
  })
132
92
 
133
93
  test('Should expose router options via getters on request and reply', t => {
134
- t.plan(7)
94
+ t.plan(10)
135
95
  const fastify = Fastify()
96
+ const expectedSchema = {
97
+ params: {
98
+ id: { type: 'integer' }
99
+ }
100
+ }
136
101
 
137
- fastify.get('/test/:id', (req, reply) => {
102
+ fastify.get('/test/:id', {
103
+ schema: expectedSchema
104
+ }, (req, reply) => {
138
105
  t.equal(reply.context.config.url, '/test/:id')
139
106
  t.equal(reply.context.config.method, 'GET')
107
+ t.equal(req.routeConfig.url, '/test/:id')
108
+ t.equal(req.routeConfig.method, 'GET')
109
+ t.same(req.routeSchema, expectedSchema)
140
110
  t.equal(req.routerPath, '/test/:id')
141
111
  t.equal(req.routerMethod, 'GET')
142
112
  t.equal(req.is404, false)
@@ -170,7 +140,7 @@ test('Should set is404 flag for unmatched paths', t => {
170
140
  })
171
141
  })
172
142
 
173
- test('Should honor frameworkErrors option', t => {
143
+ test('Should honor frameworkErrors option - FST_ERR_BAD_URL', t => {
174
144
  t.plan(3)
175
145
  const fastify = Fastify({
176
146
  frameworkErrors: function (err, req, res) {
@@ -198,3 +168,54 @@ test('Should honor frameworkErrors option', t => {
198
168
  }
199
169
  )
200
170
  })
171
+
172
+ test('Should honor frameworkErrors option - FST_ERR_ASYNC_CONSTRAINT', t => {
173
+ t.plan(3)
174
+
175
+ const constraint = {
176
+ name: 'secret',
177
+ storage: function () {
178
+ const secrets = {}
179
+ return {
180
+ get: (secret) => { return secrets[secret] || null },
181
+ set: (secret, store) => { secrets[secret] = store }
182
+ }
183
+ },
184
+ deriveConstraint: (req, ctx, done) => {
185
+ done(Error('kaboom'))
186
+ },
187
+ validate () { return true }
188
+ }
189
+
190
+ const fastify = Fastify({
191
+ frameworkErrors: function (err, req, res) {
192
+ if (err instanceof FST_ERR_ASYNC_CONSTRAINT) {
193
+ t.ok(true)
194
+ } else {
195
+ t.fail()
196
+ }
197
+ res.send(`${err.message} - ${err.code}`)
198
+ },
199
+ constraints: { secret: constraint }
200
+ })
201
+
202
+ fastify.route({
203
+ method: 'GET',
204
+ url: '/',
205
+ constraints: { secret: 'alpha' },
206
+ handler: (req, reply) => {
207
+ reply.send({ hello: 'from alpha' })
208
+ }
209
+ })
210
+
211
+ fastify.inject(
212
+ {
213
+ method: 'GET',
214
+ url: '/'
215
+ },
216
+ (err, res) => {
217
+ t.error(err)
218
+ t.equal(res.body, 'Unexpected error from async constraint - FST_ERR_ASYNC_CONSTRAINT')
219
+ }
220
+ )
221
+ })
@@ -1779,3 +1779,28 @@ test('Should return a human-friendly error if response status codes are not spec
1779
1779
  t.match(err.message, 'Failed building the serialization schema for GET: /, due to error response schemas should be nested under a valid status code, e.g { 2xx: { type: "object" } }')
1780
1780
  })
1781
1781
  })
1782
+
1783
+ test('setSchemaController: custom validator instance should not mutate headers schema', async t => {
1784
+ t.plan(2)
1785
+ class Headers {}
1786
+ const fastify = Fastify()
1787
+
1788
+ fastify.setSchemaController({
1789
+ compilersFactory: {
1790
+ buildValidator: function () {
1791
+ return ({ schema, method, url, httpPart }) => {
1792
+ t.type(schema, Headers)
1793
+ return () => {}
1794
+ }
1795
+ }
1796
+ }
1797
+ })
1798
+
1799
+ fastify.get('/', {
1800
+ schema: {
1801
+ headers: new Headers()
1802
+ }
1803
+ }, () => {})
1804
+
1805
+ await fastify.ready()
1806
+ })
@@ -1017,3 +1017,22 @@ test("The same $id in route's schema must not overwrite others", t => {
1017
1017
  t.same(res.payload, 'ok')
1018
1018
  })
1019
1019
  })
1020
+
1021
+ test('Custom validator compiler should not mutate schema', async t => {
1022
+ t.plan(2)
1023
+ class Headers {}
1024
+ const fastify = Fastify()
1025
+
1026
+ fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => {
1027
+ t.type(schema, Headers)
1028
+ return () => {}
1029
+ })
1030
+
1031
+ fastify.get('/', {
1032
+ schema: {
1033
+ headers: new Headers()
1034
+ }
1035
+ }, () => {})
1036
+
1037
+ await fastify.ready()
1038
+ })
@@ -1,18 +1,17 @@
1
1
  'use strict'
2
2
 
3
3
  const t = require('tap')
4
+ const sget = require('simple-get').concat
4
5
  const test = t.test
5
6
  const fastify = require('..')()
6
7
 
7
8
  const schema = {
8
- schema: {
9
- response: {
10
- '2xx': {
11
- type: 'object',
12
- properties: {
13
- hello: {
14
- type: 'string'
15
- }
9
+ response: {
10
+ '2xx': {
11
+ type: 'object',
12
+ properties: {
13
+ hello: {
14
+ type: 'string'
16
15
  }
17
16
  }
18
17
  }
@@ -20,35 +19,45 @@ const schema = {
20
19
  }
21
20
 
22
21
  const querySchema = {
23
- schema: {
24
- querystring: {
25
- type: 'object',
26
- properties: {
27
- hello: {
28
- type: 'integer'
29
- }
22
+ querystring: {
23
+ type: 'object',
24
+ properties: {
25
+ hello: {
26
+ type: 'integer'
30
27
  }
31
28
  }
32
29
  }
33
30
  }
34
31
 
35
32
  const paramsSchema = {
36
- schema: {
37
- params: {
38
- type: 'object',
39
- properties: {
40
- foo: {
41
- type: 'string'
42
- },
43
- test: {
44
- type: 'integer'
45
- }
33
+ params: {
34
+ type: 'object',
35
+ properties: {
36
+ foo: {
37
+ type: 'string'
38
+ },
39
+ test: {
40
+ type: 'integer'
46
41
  }
47
42
  }
48
43
  }
49
44
  }
50
45
 
51
- test('shorthand - search', t => {
46
+ const bodySchema = {
47
+ body: {
48
+ type: 'object',
49
+ properties: {
50
+ foo: {
51
+ type: 'string'
52
+ },
53
+ test: {
54
+ type: 'integer'
55
+ }
56
+ }
57
+ }
58
+ }
59
+
60
+ test('search', t => {
52
61
  t.plan(1)
53
62
  try {
54
63
  fastify.route({
@@ -65,13 +74,13 @@ test('shorthand - search', t => {
65
74
  }
66
75
  })
67
76
 
68
- test('shorthand - search params', t => {
77
+ test('search, params schema', t => {
69
78
  t.plan(1)
70
79
  try {
71
80
  fastify.route({
72
81
  method: 'SEARCH',
73
82
  url: '/params/:foo/:test',
74
- paramsSchema,
83
+ schema: paramsSchema,
75
84
  handler: function (request, reply) {
76
85
  reply.code(200).send(request.params)
77
86
  }
@@ -82,13 +91,13 @@ test('shorthand - search params', t => {
82
91
  }
83
92
  })
84
93
 
85
- test('shorthand - get, querystring schema', t => {
94
+ test('search, querystring schema', t => {
86
95
  t.plan(1)
87
96
  try {
88
97
  fastify.route({
89
98
  method: 'SEARCH',
90
99
  url: '/query',
91
- querySchema,
100
+ schema: querySchema,
92
101
  handler: function (request, reply) {
93
102
  reply.code(200).send(request.query)
94
103
  }
@@ -98,3 +107,133 @@ test('shorthand - get, querystring schema', t => {
98
107
  t.fail()
99
108
  }
100
109
  })
110
+
111
+ test('search, body schema', t => {
112
+ t.plan(1)
113
+ try {
114
+ fastify.route({
115
+ method: 'SEARCH',
116
+ url: '/body',
117
+ schema: bodySchema,
118
+ handler: function (request, reply) {
119
+ reply.code(200).send(request.body)
120
+ }
121
+ })
122
+ t.pass()
123
+ } catch (e) {
124
+ t.fail()
125
+ }
126
+ })
127
+
128
+ fastify.listen({ port: 0 }, err => {
129
+ t.error(err)
130
+ t.teardown(() => { fastify.close() })
131
+
132
+ const url = `http://localhost:${fastify.server.address().port}`
133
+
134
+ test('request - search', t => {
135
+ t.plan(4)
136
+ sget({
137
+ method: 'SEARCH',
138
+ url
139
+ }, (err, response, body) => {
140
+ t.error(err)
141
+ t.equal(response.statusCode, 200)
142
+ t.equal(response.headers['content-length'], '' + body.length)
143
+ t.same(JSON.parse(body), { hello: 'world' })
144
+ })
145
+ })
146
+
147
+ test('request search params schema', t => {
148
+ t.plan(4)
149
+ sget({
150
+ method: 'SEARCH',
151
+ url: `${url}/params/world/123`
152
+ }, (err, response, body) => {
153
+ t.error(err)
154
+ t.equal(response.statusCode, 200)
155
+ t.equal(response.headers['content-length'], '' + body.length)
156
+ t.same(JSON.parse(body), { foo: 'world', test: 123 })
157
+ })
158
+ })
159
+
160
+ test('request search params schema error', t => {
161
+ t.plan(3)
162
+ sget({
163
+ method: 'SEARCH',
164
+ url: `${url}/params/world/string`
165
+ }, (err, response, body) => {
166
+ t.error(err)
167
+ t.equal(response.statusCode, 400)
168
+ t.same(JSON.parse(body), {
169
+ error: 'Bad Request',
170
+ message: 'params/test must be integer',
171
+ statusCode: 400
172
+ })
173
+ })
174
+ })
175
+
176
+ test('request search querystring schema', t => {
177
+ t.plan(4)
178
+ sget({
179
+ method: 'SEARCH',
180
+ url: `${url}/query?hello=123`
181
+ }, (err, response, body) => {
182
+ t.error(err)
183
+ t.equal(response.statusCode, 200)
184
+ t.equal(response.headers['content-length'], '' + body.length)
185
+ t.same(JSON.parse(body), { hello: 123 })
186
+ })
187
+ })
188
+
189
+ test('request search querystring schema error', t => {
190
+ t.plan(3)
191
+ sget({
192
+ method: 'SEARCH',
193
+ url: `${url}/query?hello=world`
194
+ }, (err, response, body) => {
195
+ t.error(err)
196
+ t.equal(response.statusCode, 400)
197
+ t.same(JSON.parse(body), {
198
+ error: 'Bad Request',
199
+ message: 'querystring/hello must be integer',
200
+ statusCode: 400
201
+ })
202
+ })
203
+ })
204
+
205
+ test('request search body schema', t => {
206
+ t.plan(4)
207
+ const replyBody = { foo: 'bar', test: 5 }
208
+ sget({
209
+ method: 'SEARCH',
210
+ url: `${url}/body`,
211
+ body: JSON.stringify(replyBody),
212
+ headers: { 'content-type': 'application/json' }
213
+ }, (err, response, body) => {
214
+ t.error(err)
215
+ t.equal(response.statusCode, 200)
216
+ t.equal(response.headers['content-length'], '' + body.length)
217
+ t.same(JSON.parse(body), replyBody)
218
+ })
219
+ })
220
+
221
+ test('request search body schema error', t => {
222
+ t.plan(4)
223
+ sget({
224
+ method: 'SEARCH',
225
+ url: `${url}/body`,
226
+ body: JSON.stringify({ foo: 'bar', test: 'test' }),
227
+ headers: { 'content-type': 'application/json' }
228
+ }, (err, response, body) => {
229
+ t.error(err)
230
+ t.equal(response.statusCode, 400)
231
+ t.equal(response.headers['content-length'], '' + body.length)
232
+ t.same(JSON.parse(body), {
233
+ error: 'Bad Request',
234
+ message: 'body/test must be integer',
235
+ statusCode: 400
236
+ })
237
+ })
238
+ })
239
+ })
@@ -0,0 +1,54 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const test = t.test
5
+ const Fastify = require('..')
6
+
7
+ test('listen should accept null port', t => {
8
+ t.plan(1)
9
+
10
+ const fastify = Fastify()
11
+ t.teardown(fastify.close.bind(fastify))
12
+ fastify.listen({ port: null }, (err) => {
13
+ t.error(err)
14
+ })
15
+ })
16
+
17
+ test('listen should accept undefined port', t => {
18
+ t.plan(1)
19
+
20
+ const fastify = Fastify()
21
+ t.teardown(fastify.close.bind(fastify))
22
+ fastify.listen({ port: undefined }, (err) => {
23
+ t.error(err)
24
+ })
25
+ })
26
+
27
+ test('listen should accept stringified number port', t => {
28
+ t.plan(1)
29
+
30
+ const fastify = Fastify()
31
+ t.teardown(fastify.close.bind(fastify))
32
+ fastify.listen({ port: '1234' }, (err) => {
33
+ t.error(err)
34
+ })
35
+ })
36
+
37
+ test('listen should reject string port', async (t) => {
38
+ t.plan(2)
39
+
40
+ const fastify = Fastify()
41
+ t.teardown(fastify.close.bind(fastify))
42
+
43
+ try {
44
+ await fastify.listen({ port: 'hello-world' })
45
+ } catch (error) {
46
+ t.same(error.message, 'options.port should be >= 0 and < 65536. Received hello-world.')
47
+ }
48
+
49
+ try {
50
+ await fastify.listen({ port: '1234hello' })
51
+ } catch (error) {
52
+ t.same(error.message, 'options.port should be >= 0 and < 65536. Received 1234hello.')
53
+ }
54
+ })