fastify 5.3.3 → 5.5.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 (137) hide show
  1. package/.vscode/settings.json +15 -15
  2. package/LICENSE +1 -1
  3. package/README.md +2 -0
  4. package/SECURITY.md +158 -2
  5. package/build/build-validation.js +20 -1
  6. package/docs/Guides/Delay-Accepting-Requests.md +8 -5
  7. package/docs/Guides/Ecosystem.md +20 -5
  8. package/docs/Guides/Migration-Guide-V5.md +6 -10
  9. package/docs/Guides/Recommendations.md +1 -1
  10. package/docs/Reference/ContentTypeParser.md +1 -1
  11. package/docs/Reference/Errors.md +5 -3
  12. package/docs/Reference/Hooks.md +16 -20
  13. package/docs/Reference/Lifecycle.md +2 -2
  14. package/docs/Reference/Logging.md +3 -3
  15. package/docs/Reference/Middleware.md +1 -1
  16. package/docs/Reference/Reply.md +8 -8
  17. package/docs/Reference/Request.md +2 -2
  18. package/docs/Reference/Routes.md +7 -6
  19. package/docs/Reference/Server.md +341 -200
  20. package/docs/Reference/TypeScript.md +1 -3
  21. package/docs/Reference/Validation-and-Serialization.md +56 -4
  22. package/docs/Reference/Warnings.md +2 -1
  23. package/fastify.d.ts +4 -3
  24. package/fastify.js +47 -34
  25. package/lib/configValidator.js +196 -28
  26. package/lib/contentTypeParser.js +41 -48
  27. package/lib/error-handler.js +3 -3
  28. package/lib/errors.js +11 -0
  29. package/lib/handleRequest.js +13 -17
  30. package/lib/pluginOverride.js +3 -1
  31. package/lib/promise.js +23 -0
  32. package/lib/reply.js +24 -30
  33. package/lib/request.js +3 -10
  34. package/lib/route.js +37 -3
  35. package/lib/server.js +36 -35
  36. package/lib/symbols.js +1 -0
  37. package/lib/warnings.js +19 -1
  38. package/package.json +14 -10
  39. package/test/404s.test.js +226 -325
  40. package/test/allow-unsafe-regex.test.js +19 -48
  41. package/test/als.test.js +28 -40
  42. package/test/async-await.test.js +84 -128
  43. package/test/async_hooks.test.js +18 -37
  44. package/test/body-limit.test.js +90 -63
  45. package/test/buffer.test.js +22 -0
  46. package/test/build-certificate.js +1 -1
  47. package/test/case-insensitive.test.js +44 -65
  48. package/test/check.test.js +17 -21
  49. package/test/close-pipelining.test.js +24 -15
  50. package/test/constrained-routes.test.js +231 -0
  51. package/test/custom-http-server.test.js +7 -15
  52. package/test/custom-parser-async.test.js +17 -22
  53. package/test/custom-parser.0.test.js +267 -348
  54. package/test/custom-parser.1.test.js +141 -191
  55. package/test/custom-parser.2.test.js +34 -44
  56. package/test/custom-parser.3.test.js +56 -104
  57. package/test/custom-parser.4.test.js +106 -144
  58. package/test/custom-parser.5.test.js +56 -75
  59. package/test/custom-querystring-parser.test.js +51 -77
  60. package/test/decorator-namespace.test._js_ +3 -4
  61. package/test/decorator.test.js +76 -259
  62. package/test/delete.test.js +101 -110
  63. package/test/diagnostics-channel/404.test.js +7 -15
  64. package/test/diagnostics-channel/async-delay-request.test.js +7 -16
  65. package/test/diagnostics-channel/async-request.test.js +8 -16
  66. package/test/diagnostics-channel/error-request.test.js +7 -15
  67. package/test/diagnostics-channel/sync-delay-request.test.js +7 -16
  68. package/test/diagnostics-channel/sync-request-reply.test.js +9 -16
  69. package/test/diagnostics-channel/sync-request.test.js +9 -16
  70. package/test/fastify-instance.test.js +1 -1
  71. package/test/header-overflow.test.js +18 -29
  72. package/test/helper.js +139 -135
  73. package/test/hooks-async.test.js +259 -235
  74. package/test/hooks.test.js +951 -996
  75. package/test/http-methods/copy.test.js +14 -19
  76. package/test/http-methods/get.test.js +131 -143
  77. package/test/http-methods/head.test.js +53 -84
  78. package/test/http-methods/lock.test.js +31 -31
  79. package/test/http-methods/mkcalendar.test.js +45 -72
  80. package/test/http-methods/mkcol.test.js +5 -9
  81. package/test/http-methods/move.test.js +6 -10
  82. package/test/http-methods/propfind.test.js +34 -44
  83. package/test/http-methods/proppatch.test.js +23 -29
  84. package/test/http-methods/report.test.js +44 -69
  85. package/test/http-methods/search.test.js +67 -82
  86. package/test/http-methods/unlock.test.js +5 -9
  87. package/test/http2/closing.test.js +38 -20
  88. package/test/http2/secure-with-fallback.test.js +31 -28
  89. package/test/https/custom-https-server.test.js +9 -13
  90. package/test/https/https.test.js +56 -53
  91. package/test/input-validation.js +139 -150
  92. package/test/internals/errors.test.js +50 -1
  93. package/test/internals/handle-request.test.js +72 -65
  94. package/test/internals/promise.test.js +63 -0
  95. package/test/internals/reply.test.js +277 -496
  96. package/test/issue-4959.test.js +12 -3
  97. package/test/listen.4.test.js +31 -43
  98. package/test/nullable-validation.test.js +33 -46
  99. package/test/output-validation.test.js +24 -26
  100. package/test/plugin.1.test.js +40 -68
  101. package/test/plugin.2.test.js +108 -120
  102. package/test/plugin.3.test.js +50 -72
  103. package/test/plugin.4.test.js +124 -119
  104. package/test/promises.test.js +42 -63
  105. package/test/proto-poisoning.test.js +78 -97
  106. package/test/register.test.js +8 -18
  107. package/test/request-error.test.js +57 -146
  108. package/test/request-id.test.js +30 -49
  109. package/test/route-hooks.test.js +117 -101
  110. package/test/route-prefix.test.js +194 -133
  111. package/test/route-shorthand.test.js +9 -27
  112. package/test/route.1.test.js +74 -131
  113. package/test/route.8.test.js +9 -17
  114. package/test/router-options.test.js +450 -0
  115. package/test/schema-serialization.test.js +177 -154
  116. package/test/schema-special-usage.test.js +165 -132
  117. package/test/schema-validation.test.js +254 -218
  118. package/test/server.test.js +143 -5
  119. package/test/set-error-handler.test.js +58 -1
  120. package/test/skip-reply-send.test.js +64 -69
  121. package/test/stream.1.test.js +33 -50
  122. package/test/stream.4.test.js +18 -28
  123. package/test/stream.5.test.js +11 -19
  124. package/test/trust-proxy.test.js +32 -58
  125. package/test/types/errors.test-d.ts +13 -1
  126. package/test/types/fastify.test-d.ts +3 -0
  127. package/test/types/request.test-d.ts +1 -0
  128. package/test/types/type-provider.test-d.ts +55 -0
  129. package/test/url-rewriting.test.js +45 -62
  130. package/test/use-semicolon-delimiter.test.js +117 -59
  131. package/test/versioned-routes.test.js +39 -56
  132. package/types/errors.d.ts +11 -1
  133. package/types/hooks.d.ts +1 -1
  134. package/types/instance.d.ts +1 -1
  135. package/types/reply.d.ts +2 -2
  136. package/types/request.d.ts +1 -0
  137. package/.taprc +0 -7
@@ -1,12 +1,11 @@
1
1
  'use strict'
2
2
 
3
3
  const Fastify = require('../fastify')
4
- const sget = require('simple-get').concat
5
4
  const zlib = require('node:zlib')
6
5
  const { test } = require('node:test')
7
6
 
8
- test('bodyLimit', (t, done) => {
9
- t.plan(5)
7
+ test('bodyLimit', async t => {
8
+ t.plan(4)
10
9
 
11
10
  try {
12
11
  Fastify({ bodyLimit: 1.3 })
@@ -28,22 +27,17 @@ test('bodyLimit', (t, done) => {
28
27
  reply.send({ error: 'handler should not be called' })
29
28
  })
30
29
 
31
- fastify.listen({ port: 0 }, function (err) {
32
- t.assert.ifError(err)
33
- t.after(() => { fastify.close() })
30
+ const fastifyServer = await fastify.listen({ port: 0 })
31
+ t.after(() => { fastify.close() })
34
32
 
35
- sget({
36
- method: 'POST',
37
- url: 'http://localhost:' + fastify.server.address().port,
38
- headers: { 'Content-Type': 'application/json' },
39
- body: [],
40
- json: true
41
- }, (err, response, body) => {
42
- t.assert.ifError(err)
43
- t.assert.strictEqual(response.statusCode, 413)
44
- done()
45
- })
33
+ const result = await fetch(fastifyServer, {
34
+ method: 'POST',
35
+ headers: { 'Content-Type': 'application/json' },
36
+ body: JSON.stringify([])
46
37
  })
38
+
39
+ t.assert.ok(!result.ok)
40
+ t.assert.strictEqual(result.status, 413)
47
41
  })
48
42
 
49
43
  test('bodyLimit is applied to decoded content', async (t) => {
@@ -114,8 +108,8 @@ test('bodyLimit is applied to decoded content', async (t) => {
114
108
  })
115
109
  })
116
110
 
117
- test('default request.routeOptions.bodyLimit should be 1048576', (t, done) => {
118
- t.plan(4)
111
+ test('default request.routeOptions.bodyLimit should be 1048576', async t => {
112
+ t.plan(3)
119
113
  const fastify = Fastify()
120
114
  fastify.post('/default-bodylimit', {
121
115
  handler (request, reply) {
@@ -123,26 +117,20 @@ test('default request.routeOptions.bodyLimit should be 1048576', (t, done) => {
123
117
  reply.send({ })
124
118
  }
125
119
  })
126
- fastify.listen({ port: 0 }, function (err) {
127
- t.assert.ifError(err)
128
- t.after(() => { fastify.close() })
120
+ const fastifyServer = await fastify.listen({ port: 0 })
121
+ t.after(() => { fastify.close() })
129
122
 
130
- sget({
131
- method: 'POST',
132
- url: 'http://localhost:' + fastify.server.address().port + '/default-bodylimit',
133
- headers: { 'Content-Type': 'application/json' },
134
- body: [],
135
- json: true
136
- }, (err, response, body) => {
137
- t.assert.ifError(err)
138
- t.assert.strictEqual(response.statusCode, 200)
139
- done()
140
- })
123
+ const result = await fetch(fastifyServer + '/default-bodylimit', {
124
+ method: 'POST',
125
+ headers: { 'Content-Type': 'application/json' },
126
+ body: JSON.stringify([])
141
127
  })
128
+ t.assert.ok(result.ok)
129
+ t.assert.strictEqual(result.status, 200)
142
130
  })
143
131
 
144
- test('request.routeOptions.bodyLimit should be equal to route limit', (t, done) => {
145
- t.plan(4)
132
+ test('request.routeOptions.bodyLimit should be equal to route limit', async t => {
133
+ t.plan(3)
146
134
  const fastify = Fastify({ bodyLimit: 1 })
147
135
  fastify.post('/route-limit', {
148
136
  bodyLimit: 1000,
@@ -151,26 +139,20 @@ test('request.routeOptions.bodyLimit should be equal to route limit', (t, done)
151
139
  reply.send({})
152
140
  }
153
141
  })
154
- fastify.listen({ port: 0 }, function (err) {
155
- t.assert.ifError(err)
156
- t.after(() => { fastify.close() })
142
+ const fastifyServer = await fastify.listen({ port: 0 })
143
+ t.after(() => { fastify.close() })
157
144
 
158
- sget({
159
- method: 'POST',
160
- url: 'http://localhost:' + fastify.server.address().port + '/route-limit',
161
- headers: { 'Content-Type': 'application/json' },
162
- body: [],
163
- json: true
164
- }, (err, response, body) => {
165
- t.assert.ifError(err)
166
- t.assert.strictEqual(response.statusCode, 200)
167
- done()
168
- })
145
+ const result = await fetch(fastifyServer + '/route-limit', {
146
+ method: 'POST',
147
+ headers: { 'Content-Type': 'application/json' },
148
+ body: JSON.stringify([])
169
149
  })
150
+ t.assert.ok(result.ok)
151
+ t.assert.strictEqual(result.status, 200)
170
152
  })
171
153
 
172
- test('request.routeOptions.bodyLimit should be equal to server limit', (t, done) => {
173
- t.plan(4)
154
+ test('request.routeOptions.bodyLimit should be equal to server limit', async t => {
155
+ t.plan(3)
174
156
  const fastify = Fastify({ bodyLimit: 100 })
175
157
  fastify.post('/server-limit', {
176
158
  handler (request, reply) {
@@ -178,20 +160,65 @@ test('request.routeOptions.bodyLimit should be equal to server limit', (t, done)
178
160
  reply.send({})
179
161
  }
180
162
  })
181
- fastify.listen({ port: 0 }, function (err) {
182
- t.assert.ifError(err)
183
- t.after(() => { fastify.close() })
163
+ const fastifyServer = await fastify.listen({ port: 0 })
164
+ t.after(() => { fastify.close() })
165
+
166
+ const result = await fetch(fastifyServer + '/server-limit', {
167
+ method: 'POST',
168
+ headers: { 'Content-Type': 'application/json' },
169
+ body: JSON.stringify([])
170
+ })
171
+ t.assert.ok(result.ok)
172
+ t.assert.strictEqual(result.status, 200)
173
+ })
184
174
 
185
- sget({
175
+ test('bodyLimit should use byte length for UTF-8 strings, not character length', async t => {
176
+ t.plan(4)
177
+
178
+ // Create a string with multi-byte UTF-8 characters
179
+ // Use Japanese characters that are 3 bytes each in UTF-8
180
+ const multiByteString = 'あああ' // 3 characters, 9 bytes in UTF-8
181
+ t.assert.strictEqual(multiByteString.length, 3) // 3 characters
182
+ t.assert.strictEqual(Buffer.byteLength(multiByteString, 'utf8'), 9) // 9 bytes
183
+
184
+ const fastify = Fastify()
185
+
186
+ // Add a custom text parser that returns the string as-is
187
+ fastify.addContentTypeParser('text/plain', { parseAs: 'string' }, (req, body, done) => {
188
+ done(null, body)
189
+ })
190
+
191
+ // Set body limit to 7 bytes - this should reject the string (9 bytes)
192
+ // even though string.length (3) would be under any reasonable limit
193
+ fastify.post('/test-utf8', {
194
+ bodyLimit: 7
195
+ }, (request, reply) => {
196
+ reply.send({ body: request.body, length: request.body.length })
197
+ })
198
+
199
+ await t.test('should reject body when byte length exceeds limit', async (t) => {
200
+ const result = await fastify.inject({
186
201
  method: 'POST',
187
- url: 'http://localhost:' + fastify.server.address().port + '/server-limit',
188
- headers: { 'Content-Type': 'application/json' },
189
- body: [],
190
- json: true
191
- }, (err, response, body) => {
192
- t.assert.ifError(err)
193
- t.assert.strictEqual(response.statusCode, 200)
194
- done()
202
+ url: '/test-utf8',
203
+ headers: { 'Content-Type': 'text/plain', 'Content-Length': null },
204
+ payload: multiByteString
195
205
  })
206
+
207
+ t.assert.strictEqual(result.statusCode, 413)
208
+ })
209
+
210
+ await t.test('should accept body when byte length is within limit', async (t) => {
211
+ const smallString = 'あ' // 1 character, 3 bytes, under the 7 byte limit
212
+
213
+ const result = await fastify.inject({
214
+ method: 'POST',
215
+ url: '/test-utf8',
216
+ headers: { 'Content-Type': 'text/plain' },
217
+ payload: smallString
218
+ })
219
+
220
+ t.assert.strictEqual(result.statusCode, 200)
221
+ t.assert.strictEqual(result.json().body, smallString)
222
+ t.assert.strictEqual(result.json().length, 1) // 1 character
196
223
  })
197
224
  })
@@ -49,4 +49,26 @@ test('Buffer test', async t => {
49
49
  statusCode: 400
50
50
  })
51
51
  })
52
+
53
+ await test('should return 400 if the body is invalid json', async t => {
54
+ t.plan(3)
55
+
56
+ const response = await fastify.inject({
57
+ method: 'DELETE',
58
+ url: '/',
59
+ payload: Buffer.from(']'),
60
+ headers: {
61
+ 'content-type': 'application/json'
62
+ }
63
+ })
64
+
65
+ t.assert.ifError(response.error)
66
+ t.assert.strictEqual(response.statusCode, 400)
67
+ t.assert.deepStrictEqual(JSON.parse(response.payload.toString()), {
68
+ error: 'Bad Request',
69
+ code: 'FST_ERR_CTP_INVALID_JSON_BODY',
70
+ message: 'Body is not valid JSON but content-type is set to \'application/json\'',
71
+ statusCode: 400
72
+ })
73
+ })
52
74
  })
@@ -91,7 +91,7 @@ function selfCert (opts) {
91
91
  }
92
92
  }
93
93
 
94
- async function buildCertificate () {
94
+ function buildCertificate () {
95
95
  // "global" is used in here because "t.context" is only supported by "t.beforeEach" and "t.afterEach"
96
96
  // For the test case which execute this code which will be using `t.before` and it can reduce the
97
97
  // number of times executing it.
@@ -2,10 +2,9 @@
2
2
 
3
3
  const { test } = require('node:test')
4
4
  const Fastify = require('..')
5
- const sget = require('simple-get').concat
6
5
 
7
- test('case insensitive', (t, done) => {
8
- t.plan(4)
6
+ test('case insensitive', async (t) => {
7
+ t.plan(3)
9
8
 
10
9
  const fastify = Fastify({
11
10
  caseSensitive: false
@@ -16,25 +15,19 @@ test('case insensitive', (t, done) => {
16
15
  reply.send({ hello: 'world' })
17
16
  })
18
17
 
19
- fastify.listen({ port: 0 }, err => {
20
- t.assert.ifError(err)
21
-
22
- sget({
23
- method: 'GET',
24
- url: 'http://localhost:' + fastify.server.address().port + '/FOO'
25
- }, (err, response, body) => {
26
- t.assert.ifError(err)
27
- t.assert.strictEqual(response.statusCode, 200)
28
- t.assert.deepStrictEqual(JSON.parse(body), {
29
- hello: 'world'
30
- })
31
- done()
32
- })
18
+ const fastifyServer = await fastify.listen({ port: 0 })
19
+
20
+ const result = await fetch(`${fastifyServer}/FOO`)
21
+
22
+ t.assert.ok(result.ok)
23
+ t.assert.strictEqual(result.status, 200)
24
+ t.assert.deepStrictEqual(await result.json(), {
25
+ hello: 'world'
33
26
  })
34
27
  })
35
28
 
36
- test('case insensitive inject', (t, done) => {
37
- t.plan(4)
29
+ test('case insensitive inject', async t => {
30
+ t.plan(2)
38
31
 
39
32
  const fastify = Fastify({
40
33
  caseSensitive: false
@@ -45,25 +38,21 @@ test('case insensitive inject', (t, done) => {
45
38
  reply.send({ hello: 'world' })
46
39
  })
47
40
 
48
- fastify.listen({ port: 0 }, err => {
49
- t.assert.ifError(err)
50
-
51
- fastify.inject({
52
- method: 'GET',
53
- url: 'http://localhost:' + fastify.server.address().port + '/FOO'
54
- }, (err, response) => {
55
- t.assert.ifError(err)
56
- t.assert.strictEqual(response.statusCode, 200)
57
- t.assert.deepStrictEqual(JSON.parse(response.payload), {
58
- hello: 'world'
59
- })
60
- done()
61
- })
41
+ const fastifyServer = await fastify.listen({ port: 0 })
42
+
43
+ const result = await fastify.inject({
44
+ method: 'GET',
45
+ url: fastifyServer + '/FOO'
46
+ })
47
+
48
+ t.assert.strictEqual(result.statusCode, 200)
49
+ t.assert.deepStrictEqual(result.json(), {
50
+ hello: 'world'
62
51
  })
63
52
  })
64
53
 
65
- test('case insensitive (parametric)', (t, done) => {
66
- t.plan(5)
54
+ test('case insensitive (parametric)', async (t) => {
55
+ t.plan(4)
67
56
 
68
57
  const fastify = Fastify({
69
58
  caseSensitive: false
@@ -75,25 +64,21 @@ test('case insensitive (parametric)', (t, done) => {
75
64
  reply.send({ hello: 'world' })
76
65
  })
77
66
 
78
- fastify.listen({ port: 0 }, err => {
79
- t.assert.ifError(err)
80
-
81
- sget({
82
- method: 'GET',
83
- url: 'http://localhost:' + fastify.server.address().port + '/FoO/bAr'
84
- }, (err, response, body) => {
85
- t.assert.ifError(err)
86
- t.assert.strictEqual(response.statusCode, 200)
87
- t.assert.deepStrictEqual(JSON.parse(body), {
88
- hello: 'world'
89
- })
90
- done()
91
- })
67
+ const fastifyServer = await fastify.listen({ port: 0 })
68
+
69
+ const result = await fetch(`${fastifyServer}/FoO/bAr`, {
70
+ method: 'GET'
71
+ })
72
+
73
+ t.assert.ok(result.ok)
74
+ t.assert.strictEqual(result.status, 200)
75
+ t.assert.deepStrictEqual(await result.json(), {
76
+ hello: 'world'
92
77
  })
93
78
  })
94
79
 
95
- test('case insensitive (wildcard)', (t, done) => {
96
- t.plan(5)
80
+ test('case insensitive (wildcard)', async (t) => {
81
+ t.plan(4)
97
82
 
98
83
  const fastify = Fastify({
99
84
  caseSensitive: false
@@ -105,19 +90,13 @@ test('case insensitive (wildcard)', (t, done) => {
105
90
  reply.send({ hello: 'world' })
106
91
  })
107
92
 
108
- fastify.listen({ port: 0 }, err => {
109
- t.assert.ifError(err)
110
-
111
- sget({
112
- method: 'GET',
113
- url: 'http://localhost:' + fastify.server.address().port + '/FoO/bAr/baZ'
114
- }, (err, response, body) => {
115
- t.assert.ifError(err)
116
- t.assert.strictEqual(response.statusCode, 200)
117
- t.assert.deepStrictEqual(JSON.parse(body), {
118
- hello: 'world'
119
- })
120
- done()
121
- })
93
+ const fastifyServer = await fastify.listen({ port: 0 })
94
+
95
+ const result = await fetch(`${fastifyServer}/FoO/bAr/baZ`)
96
+
97
+ t.assert.ok(result.ok)
98
+ t.assert.strictEqual(result.status, 200)
99
+ t.assert.deepStrictEqual(await result.json(), {
100
+ hello: 'world'
122
101
  })
123
102
  })
@@ -3,7 +3,6 @@
3
3
  const { test } = require('node:test')
4
4
  const { S } = require('fluent-json-schema')
5
5
  const Fastify = require('..')
6
- const sget = require('simple-get').concat
7
6
 
8
7
  const BadRequestSchema = S.object()
9
8
  .prop('statusCode', S.number())
@@ -105,32 +104,29 @@ const handler = (request, reply) => {
105
104
  })
106
105
  }
107
106
 
108
- test('serialize the response for a Bad Request error, as defined on the schema', (t, done) => {
107
+ test('serialize the response for a Bad Request error, as defined on the schema', async t => {
109
108
  const fastify = Fastify({})
110
109
 
111
110
  t.after(() => fastify.close())
112
111
 
113
112
  fastify.post('/', options, handler)
114
113
 
115
- fastify.listen({ port: 0 }, err => {
116
- t.assert.ifError(err)
117
-
118
- const url = `http://localhost:${fastify.server.address().port}/`
119
-
120
- sget({
121
- method: 'POST',
122
- url,
123
- json: true
124
- }, (err, response, body) => {
125
- t.assert.ifError(err)
126
- t.assert.strictEqual(response.statusCode, 400)
127
- t.assert.deepStrictEqual(body, {
128
- statusCode: 400,
129
- error: 'Bad Request',
130
- message: 'body must be object'
131
- })
132
- done()
133
- })
114
+ const fastifyServer = await fastify.listen({ port: 0 })
115
+
116
+ const result = await fetch(fastifyServer, {
117
+ method: 'POST',
118
+ headers: {
119
+ 'Content-Type': 'application/json'
120
+ },
121
+ body: '12'
122
+ })
123
+
124
+ t.assert.ok(!result.ok)
125
+ t.assert.strictEqual(result.status, 400)
126
+ t.assert.deepStrictEqual(await result.json(), {
127
+ statusCode: 400,
128
+ error: 'Bad Request',
129
+ message: 'body must be object'
134
130
  })
135
131
  })
136
132
 
@@ -11,8 +11,10 @@ test('Should return 503 while closing - pipelining', async t => {
11
11
  })
12
12
 
13
13
  fastify.get('/', async (req, reply) => {
14
+ // Simulate a delay to allow pipelining to kick in
15
+ await new Promise(resolve => setTimeout(resolve, 5))
16
+ reply.send({ hello: 'world' })
14
17
  fastify.close()
15
- return { hello: 'world' }
16
18
  })
17
19
 
18
20
  await fastify.listen({ port: 0 })
@@ -21,14 +23,19 @@ test('Should return 503 while closing - pipelining', async t => {
21
23
  pipelining: 2
22
24
  })
23
25
 
24
- const codes = [200, 200, 503]
25
- const responses = await Promise.all([
26
- instance.request({ path: '/', method: 'GET' }),
27
- instance.request({ path: '/', method: 'GET' }),
28
- instance.request({ path: '/', method: 'GET' })
26
+ const [firstRequest, secondRequest, thirdRequest] = await Promise.allSettled([
27
+ instance.request({ path: '/', method: 'GET', blocking: false }),
28
+ instance.request({ path: '/', method: 'GET', blocking: false }),
29
+ instance.request({ path: '/', method: 'GET', blocking: false })
29
30
  ])
30
- const actual = responses.map(r => r.statusCode)
31
- t.assert.deepStrictEqual(actual, codes)
31
+ t.assert.strictEqual(firstRequest.status, 'fulfilled')
32
+ t.assert.strictEqual(secondRequest.status, 'fulfilled')
33
+
34
+ t.assert.strictEqual(firstRequest.value.statusCode, 200)
35
+ t.assert.strictEqual(secondRequest.value.statusCode, 200)
36
+
37
+ t.assert.strictEqual(thirdRequest.status, 'fulfilled')
38
+ t.assert.strictEqual(thirdRequest.value.statusCode, 503)
32
39
 
33
40
  await instance.close()
34
41
  })
@@ -42,6 +49,8 @@ test('Should close the socket abruptly - pipelining - return503OnClosing: false'
42
49
  })
43
50
 
44
51
  fastify.get('/', async (req, reply) => {
52
+ // Simulate a delay to allow pipelining to kick in
53
+ await new Promise(resolve => setTimeout(resolve, 5))
45
54
  reply.send({ hello: 'world' })
46
55
  fastify.close()
47
56
  })
@@ -49,21 +58,21 @@ test('Should close the socket abruptly - pipelining - return503OnClosing: false'
49
58
  await fastify.listen({ port: 0 })
50
59
 
51
60
  const instance = new Client('http://localhost:' + fastify.server.address().port, {
52
- pipelining: 2
61
+ pipelining: 1
53
62
  })
54
63
 
55
64
  const responses = await Promise.allSettled([
56
- instance.request({ path: '/', method: 'GET' }),
57
- instance.request({ path: '/', method: 'GET' }),
58
- instance.request({ path: '/', method: 'GET' }),
59
- instance.request({ path: '/', method: 'GET' })
65
+ instance.request({ path: '/', method: 'GET', blocking: false }),
66
+ instance.request({ path: '/', method: 'GET', blocking: false }),
67
+ instance.request({ path: '/', method: 'GET', blocking: false }),
68
+ instance.request({ path: '/', method: 'GET', blocking: false })
60
69
  ])
61
70
 
62
71
  const fulfilled = responses.filter(r => r.status === 'fulfilled')
63
72
  const rejected = responses.filter(r => r.status === 'rejected')
64
73
 
65
- t.assert.strictEqual(fulfilled.length, 2)
66
- t.assert.strictEqual(rejected.length, 2)
74
+ t.assert.strictEqual(fulfilled.length, 1)
75
+ t.assert.strictEqual(rejected.length, 3)
67
76
 
68
77
  await instance.close()
69
78
  })