@fastify/reply-from 12.1.0 → 12.3.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 (108) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/.github/workflows/ci.yml +3 -0
  3. package/LICENSE +4 -1
  4. package/README.md +20 -0
  5. package/index.js +10 -0
  6. package/lib/request.js +13 -3
  7. package/lib/utils.js +1 -0
  8. package/package.json +6 -8
  9. package/test/async-route-handler.test.js +29 -32
  10. package/test/balanced-pool.test.js +48 -0
  11. package/test/base-get.test.js +27 -30
  12. package/test/base-path.test.js +27 -24
  13. package/test/base-querystring.test.js +27 -30
  14. package/test/build-url.test.js +17 -15
  15. package/test/core-with-path-in-base.test.js +30 -33
  16. package/test/custom-undici-instance.test.js +28 -36
  17. package/test/disable-request-logging.test.js +38 -52
  18. package/test/fastify-multipart-incompatibility.test.js +43 -49
  19. package/test/fix-GHSA-v2v2-hph8-q5xp.test.js +3 -2
  20. package/test/full-delete-http2.test.js +12 -11
  21. package/test/full-get-test.test.js +27 -30
  22. package/test/full-https-get.test.js +30 -30
  23. package/test/full-post-extended-content-type.test.js +40 -44
  24. package/test/full-post-http2.test.js +18 -13
  25. package/test/full-post-stream-core.test.js +39 -43
  26. package/test/full-post-stream.test.js +39 -43
  27. package/test/full-post.test.js +36 -38
  28. package/test/full-querystring-rewrite-option-complex.test.js +27 -31
  29. package/test/full-querystring-rewrite-option-function-request.test.js +30 -36
  30. package/test/full-querystring-rewrite-option-function.test.js +30 -33
  31. package/test/full-querystring-rewrite-option.test.js +28 -31
  32. package/test/full-querystring-rewrite-string.test.js +27 -30
  33. package/test/full-querystring-rewrite.test.js +27 -30
  34. package/test/full-querystring.test.js +27 -30
  35. package/test/full-rewrite-body-content-type.test.js +37 -41
  36. package/test/full-rewrite-body-http.test.js +39 -43
  37. package/test/full-rewrite-body-to-empty-string.test.js +37 -41
  38. package/test/full-rewrite-body-to-null.test.js +37 -41
  39. package/test/full-rewrite-body.test.js +39 -43
  40. package/test/get-upstream-cache.test.js +12 -11
  41. package/test/get-upstream-http.test.js +35 -41
  42. package/test/get-upstream-type.test.js +24 -27
  43. package/test/get-upstream-undici.test.js +23 -26
  44. package/test/host-header.test.js +22 -18
  45. package/test/http-agents.test.js +27 -30
  46. package/test/http-global-agent.test.js +20 -33
  47. package/test/http-http2.test.js +13 -18
  48. package/test/http-invalid-target.test.js +13 -17
  49. package/test/http-retry.test.js +22 -29
  50. package/test/http-timeout.test.js +49 -42
  51. package/test/http2-canceled-streams-cleanup.test.js +117 -0
  52. package/test/http2-goaway.test.js +126 -0
  53. package/test/http2-http2.test.js +8 -8
  54. package/test/http2-https.test.js +29 -27
  55. package/test/http2-invalid-base.test.js +2 -2
  56. package/test/http2-invalid-target.test.js +13 -17
  57. package/test/http2-target-crash.test.js +16 -20
  58. package/test/http2-target-multi-crash.test.js +22 -27
  59. package/test/http2-timeout-disabled.test.js +20 -15
  60. package/test/http2-timeout.test.js +58 -65
  61. package/test/http2-unix-socket.test.js +2 -2
  62. package/test/https-agents.test.js +31 -30
  63. package/test/https-global-agent.test.js +22 -31
  64. package/test/method.test.js +37 -42
  65. package/test/modifyCoreObjects-false.test.js +27 -30
  66. package/test/no-body-opts-with-get.test.js +25 -31
  67. package/test/no-body-opts-with-head.test.js +28 -32
  68. package/test/no-stream-body-option.test.js +34 -36
  69. package/test/on-error.test.js +21 -23
  70. package/test/on-invalid-upstream-response.test.js +30 -37
  71. package/test/onResponse.test.js +25 -32
  72. package/test/padded-body.test.js +38 -43
  73. package/test/post-formbody.test.js +35 -40
  74. package/test/post-plain-text.test.js +35 -39
  75. package/test/post-with-custom-encoded-contenttype.test.js +37 -39
  76. package/test/post-with-octet-stream.test.js +18 -88
  77. package/test/retry-on-503.test.js +27 -26
  78. package/test/retry-with-a-custom-handler.test.js +33 -40
  79. package/test/rewrite-headers-type.test.js +24 -29
  80. package/test/rewrite-headers.test.js +31 -36
  81. package/test/rewrite-request-headers-type.test.js +25 -28
  82. package/test/rewrite-request-headers.test.js +26 -30
  83. package/test/transform-body.test.js +37 -43
  84. package/test/undici-agent.test.js +27 -31
  85. package/test/undici-body.test.js +37 -42
  86. package/test/undici-chaining.test.js +35 -42
  87. package/test/undici-connect-timeout.test.js +13 -13
  88. package/test/undici-custom-dispatcher.test.js +11 -11
  89. package/test/undici-global-agent.test.js +14 -33
  90. package/test/undici-no-destroy.test.js +2 -2
  91. package/test/undici-options.test.js +21 -24
  92. package/test/undici-proxy-agent.test.js +4 -3
  93. package/test/undici-retry.test.js +24 -31
  94. package/test/undici-timeout-body-partial.test.js +14 -16
  95. package/test/undici-timeout-body.test.js +17 -19
  96. package/test/undici-timeout.test.js +41 -37
  97. package/test/undici-with-path-in-base.test.js +28 -31
  98. package/test/undici.test.js +28 -31
  99. package/test/unexpected-error.test.js +13 -18
  100. package/test/unix-http-undici-from.test.js +22 -31
  101. package/test/unix-http-undici.test.js +32 -40
  102. package/test/unix-http.test.js +31 -39
  103. package/test/unix-https-undici.test.js +30 -35
  104. package/test/unix-https.test.js +35 -40
  105. package/types/index.d.ts +9 -2
  106. package/types/index.test-d.ts +3 -4
  107. package/test/get-with-body.test.js +0 -55
  108. package/test/head-with-body.test.js +0 -57
@@ -1,18 +1,18 @@
1
1
  'use strict'
2
2
 
3
- const { test } = require('tap')
3
+ const { test } = require('node:test')
4
4
  const Fastify = require('fastify')
5
+ const { request, Agent } = require('undici')
5
6
  const From = require('..')
6
- const got = require('got')
7
7
  const FakeTimers = require('@sinonjs/fake-timers')
8
8
 
9
9
  test('http request timeout', async (t) => {
10
10
  const clock = FakeTimers.createClock()
11
11
  const target = Fastify()
12
- t.teardown(target.close.bind(target))
12
+ t.after(() => target.close())
13
13
 
14
14
  target.get('/', (_request, reply) => {
15
- t.pass('request arrives')
15
+ t.assert.ok('request arrives')
16
16
 
17
17
  setTimeout(() => {
18
18
  reply.status(200).send('hello world')
@@ -24,7 +24,7 @@ test('http request timeout', async (t) => {
24
24
  await target.listen({ port: 0 })
25
25
 
26
26
  const instance = Fastify()
27
- t.teardown(instance.close.bind(instance))
27
+ t.after(() => instance.close())
28
28
 
29
29
  instance.register(From, { http: { requestOptions: { timeout: 100 } } })
30
30
 
@@ -34,30 +34,30 @@ test('http request timeout', async (t) => {
34
34
 
35
35
  await instance.listen({ port: 0 })
36
36
 
37
- try {
38
- await got.get(`http://localhost:${instance.server.address().port}/`, { retry: 0 })
39
- } catch (err) {
40
- t.equal(err.response.statusCode, 504)
41
- t.match(err.response.headers['content-type'], /application\/json/)
42
- t.same(JSON.parse(err.response.body), {
43
- statusCode: 504,
44
- code: 'FST_REPLY_FROM_GATEWAY_TIMEOUT',
45
- error: 'Gateway Timeout',
46
- message: 'Gateway Timeout'
37
+ const result = await request(`http://localhost:${instance.server.address().port}/`, {
38
+ dispatcher: new Agent({
39
+ pipelining: 0
47
40
  })
48
- return
49
- }
41
+ })
50
42
 
51
- t.fail()
43
+ t.assert.strictEqual(result.statusCode, 504)
44
+ t.assert.match(result.headers['content-type'], /application\/json/)
45
+ t.assert.deepStrictEqual(await result.body.json(), {
46
+ statusCode: 504,
47
+ code: 'FST_REPLY_FROM_GATEWAY_TIMEOUT',
48
+ error: 'Gateway Timeout',
49
+ message: 'Gateway Timeout'
50
+ })
51
+ clock.tick(200)
52
52
  })
53
53
 
54
54
  test('http request with specific timeout', async (t) => {
55
55
  const clock = FakeTimers.createClock()
56
56
  const target = Fastify()
57
- t.teardown(target.close.bind(target))
57
+ t.after(() => target.close())
58
58
 
59
59
  target.get('/', (_request, reply) => {
60
- t.pass('request arrives')
60
+ t.assert.ok('request arrives')
61
61
 
62
62
  setTimeout(() => {
63
63
  reply.status(200).send('hello world')
@@ -69,7 +69,7 @@ test('http request with specific timeout', async (t) => {
69
69
  await target.listen({ port: 0 })
70
70
 
71
71
  const instance = Fastify()
72
- t.teardown(instance.close.bind(instance))
72
+ t.after(() => instance.close())
73
73
 
74
74
  instance.register(From, { http: { requestOptions: { timeout: 100 } } })
75
75
 
@@ -85,32 +85,35 @@ test('http request with specific timeout', async (t) => {
85
85
  })
86
86
 
87
87
  await instance.listen({ port: 0 })
88
- const { statusCode } = await got.get(`http://localhost:${instance.server.address().port}/success`, { retry: 0 })
89
- t.equal(statusCode, 200)
90
-
91
- try {
92
- await got.get(`http://localhost:${instance.server.address().port}/fail`, { retry: 0 })
93
- } catch (err) {
94
- t.equal(err.response.statusCode, 504)
95
- t.match(err.response.headers['content-type'], /application\/json/)
96
- t.same(JSON.parse(err.response.body), {
97
- statusCode: 504,
98
- code: 'FST_REPLY_FROM_GATEWAY_TIMEOUT',
99
- error: 'Gateway Timeout',
100
- message: 'Gateway Timeout'
88
+ const result = await request(`http://localhost:${instance.server.address().port}/success`, {
89
+ dispatcher: new Agent({
90
+ pipelining: 0
101
91
  })
102
- return
103
- }
92
+ })
93
+ t.assert.strictEqual(result.statusCode, 200)
104
94
 
105
- t.fail()
95
+ const result2 = await request(`http://localhost:${instance.server.address().port}/fail`, {
96
+ dispatcher: new Agent({
97
+ pipelining: 0
98
+ })
99
+ })
100
+
101
+ t.assert.strictEqual(result2.statusCode, 504)
102
+ t.assert.match(result2.headers['content-type'], /application\/json/)
103
+ t.assert.deepStrictEqual(await result2.body.json(), {
104
+ statusCode: 504,
105
+ code: 'FST_REPLY_FROM_GATEWAY_TIMEOUT',
106
+ error: 'Gateway Timeout',
107
+ message: 'Gateway Timeout'
108
+ })
106
109
  })
107
110
 
108
111
  test('http sse removes timeout test', async (t) => {
109
112
  const target = Fastify()
110
- t.teardown(target.close.bind(target))
113
+ t.after(() => target.close())
111
114
 
112
115
  target.get('/', (_request, reply) => {
113
- t.pass('request arrives')
116
+ t.assert.ok('request arrives')
114
117
 
115
118
  reply.header('content-type', 'text/event-stream').status(200).send('hello world')
116
119
  })
@@ -118,7 +121,7 @@ test('http sse removes timeout test', async (t) => {
118
121
  await target.listen({ port: 0 })
119
122
 
120
123
  const instance = Fastify()
121
- t.teardown(instance.close.bind(instance))
124
+ t.after(() => instance.close())
122
125
 
123
126
  instance.register(From, { http: { requestOptions: { timeout: 100 } } })
124
127
 
@@ -128,6 +131,10 @@ test('http sse removes timeout test', async (t) => {
128
131
 
129
132
  await instance.listen({ port: 0 })
130
133
 
131
- const { statusCode } = await got.get(`http://localhost:${instance.server.address().port}/`, { retry: 0 })
132
- t.equal(statusCode, 200)
134
+ const { statusCode } = await request(`http://localhost:${instance.server.address().port}/`, {
135
+ dispatcher: new Agent({
136
+ pipelining: 0
137
+ })
138
+ })
139
+ t.assert.strictEqual(statusCode, 200)
133
140
  })
@@ -0,0 +1,117 @@
1
+ 'use strict'
2
+
3
+ const t = require('node:test')
4
+ const Fastify = require('fastify')
5
+ const From = require('..')
6
+ const fs = require('node:fs')
7
+ const path = require('node:path')
8
+ const http2 = require('node:http2')
9
+ const { once } = require('events')
10
+ const certs = {
11
+ key: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.key')),
12
+ cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.cert'))
13
+ }
14
+ const { HTTP2_HEADER_STATUS, HTTP2_HEADER_PATH } = http2.constants
15
+
16
+ function makeRequest (client, counter) {
17
+ return new Promise((resolve, reject) => {
18
+ const controller = new AbortController()
19
+ const signal = controller.signal
20
+ const cancelRequestEarly = counter % 2 === 0 // cancel early every other request
21
+ let responseCounter = 0
22
+
23
+ const clientStream = client.request({ [HTTP2_HEADER_PATH]: '/' }, { signal })
24
+
25
+ clientStream.end()
26
+
27
+ clientStream.on('data', chunk => {
28
+ const s = chunk.toString()
29
+ // Sometimes we just get NGHTTP2_ENHANCE_YOUR_CALM internal server errors
30
+ if (s.startsWith('{"statusCode":500')) reject(new Error('got internal server error'))
31
+ else responseCounter++
32
+ })
33
+
34
+ clientStream.on('error', err => {
35
+ if (err instanceof Error && err.name === 'AbortError') {
36
+ if (responseCounter === 0 && !cancelRequestEarly) {
37
+ // if we didn´t cancel early we should have received at least one response from the target
38
+ // if not, this indicated the stream resource leak
39
+ reject(new Error('no response'))
40
+ } else resolve()
41
+ } else reject(err instanceof Error ? err : new Error(JSON.stringify(err)))
42
+ })
43
+
44
+ clientStream.on('end', () => { resolve() })
45
+
46
+ setTimeout(() => { controller.abort() }, cancelRequestEarly ? 20 : 200)
47
+ })
48
+ }
49
+
50
+ const httpsOptions = {
51
+ ...certs,
52
+ settings: {
53
+ maxConcurrentStreams: 10, // lower the default so we can reproduce the problem quicker
54
+ }
55
+ }
56
+
57
+ t.test('http2 -> http2', async (t) => {
58
+ const instance = Fastify({
59
+ http2: true,
60
+ https: httpsOptions
61
+ })
62
+
63
+ t.after(() => instance.close())
64
+
65
+ const target = http2.createSecureServer(httpsOptions)
66
+
67
+ target.on('stream', (stream, _headers, _flags) => {
68
+ let counter = 0
69
+ let headerSent = false
70
+
71
+ // deliberately delay sending the headers
72
+ const sendData = () => {
73
+ if (!headerSent) {
74
+ stream.respond({ [HTTP2_HEADER_STATUS]: 200, })
75
+ headerSent = true
76
+ }
77
+ stream.write(counter + '\n')
78
+ counter = counter + 1
79
+ }
80
+
81
+ const intervalId = setInterval(sendData, 50)
82
+
83
+ // ignore write after end errors
84
+ stream.on('error', _err => { })
85
+
86
+ stream.on('close', () => { clearInterval(intervalId) })
87
+ })
88
+
89
+ instance.get('/', (_request, reply) => {
90
+ reply.from()
91
+ })
92
+
93
+ t.after(() => target.close())
94
+
95
+ target.listen()
96
+ await once(target, 'listening')
97
+
98
+ instance.register(From, {
99
+ base: `https://localhost:${target.address().port}`,
100
+ http2: true,
101
+ rejectUnauthorized: false
102
+ })
103
+
104
+ const url = await instance.listen({ port: 0 })
105
+
106
+ const client = http2.connect(url, {
107
+ rejectUnauthorized: false,
108
+ })
109
+
110
+ // see https://github.com/fastify/fastify-reply-from/issues/424
111
+ // without the bug fix this will fail after about 15 requests
112
+ for (let i = 0; i < 30; i++) { await makeRequest(client, i) }
113
+
114
+ client.close()
115
+ instance.close()
116
+ target.close()
117
+ })
@@ -0,0 +1,126 @@
1
+ 'use strict'
2
+
3
+ const h2url = require('h2url')
4
+ const t = require('node:test')
5
+ const Fastify = require('fastify')
6
+ const From = require('..')
7
+ const fs = require('node:fs')
8
+ const path = require('node:path')
9
+ const http2 = require('node:http2')
10
+
11
+ const certs = {
12
+ key: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.key')),
13
+ cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'fastify.cert'))
14
+ }
15
+
16
+ t.test('http2 goaway handling - reproduces issue #409', async (t) => {
17
+ let requestCount = 0
18
+
19
+ // Create a custom HTTP/2 server that sends GOAWAY after first request
20
+ const targetServer = http2.createServer()
21
+
22
+ let sessionToClose = null
23
+
24
+ targetServer.on('session', (session) => {
25
+ // Store the first session to send GOAWAY later
26
+ if (!sessionToClose) {
27
+ sessionToClose = session
28
+ }
29
+ })
30
+
31
+ targetServer.on('stream', (stream, headers) => {
32
+ requestCount++
33
+
34
+ if (requestCount === 1) {
35
+ // First request: respond normally
36
+ stream.respond({
37
+ ':status': 200,
38
+ 'content-type': 'application/json'
39
+ })
40
+ stream.end(JSON.stringify({ request: requestCount, message: 'first request' }))
41
+
42
+ // Send GOAWAY after response to close the HTTP/2 session gracefully
43
+ setTimeout(() => {
44
+ if (sessionToClose && !sessionToClose.destroyed) {
45
+ // Send GOAWAY with NO_ERROR to close gracefully
46
+ sessionToClose.goaway(0)
47
+ }
48
+ }, 50)
49
+ } else {
50
+ // Subsequent requests should work with a new session
51
+ stream.respond({
52
+ ':status': 200,
53
+ 'content-type': 'application/json'
54
+ })
55
+ stream.end(JSON.stringify({ request: requestCount, message: 'subsequent request' }))
56
+ }
57
+ })
58
+
59
+ await new Promise((resolve) => {
60
+ targetServer.listen(0, resolve)
61
+ })
62
+
63
+ const targetPort = targetServer.address().port
64
+
65
+ // Create proxy server
66
+ const instance = Fastify({
67
+ http2: true,
68
+ https: certs
69
+ })
70
+
71
+ instance.register(From, {
72
+ base: `http://localhost:${targetPort}`,
73
+ http2: true,
74
+ rejectUnauthorized: false
75
+ })
76
+
77
+ instance.get('/', (_request, reply) => {
78
+ reply.from()
79
+ })
80
+
81
+ await instance.listen({ port: 0 })
82
+
83
+ const proxyPort = instance.server.address().port
84
+
85
+ // First request - should succeed
86
+ const firstResponse = await h2url.concat({
87
+ url: `https://localhost:${proxyPort}`
88
+ })
89
+
90
+ t.assert.strictEqual(firstResponse.headers[':status'], 200)
91
+ const firstBody = JSON.parse(firstResponse.body)
92
+ t.assert.strictEqual(firstBody.request, 1)
93
+ t.assert.strictEqual(firstBody.message, 'first request')
94
+
95
+ // Wait for GOAWAY to be sent and processed
96
+ await new Promise(resolve => setTimeout(resolve, 100))
97
+
98
+ // Second request - this should fail with current implementation but work with fix
99
+ try {
100
+ const secondResponse = await h2url.concat({
101
+ url: `https://localhost:${proxyPort}`,
102
+ timeout: 1000
103
+ })
104
+
105
+ // If we get here with the current code, the request succeeded
106
+ // which means the issue might not be reproduced
107
+ t.assert.strictEqual(secondResponse.headers[':status'], 200)
108
+ const secondBody = JSON.parse(secondResponse.body)
109
+ t.assert.strictEqual(secondBody.request, 2)
110
+ t.assert.strictEqual(secondBody.message, 'subsequent request')
111
+ console.log('Second request succeeded - issue may not be reproduced or fix is already in place')
112
+ } catch (err) {
113
+ // This is expected without the fix - the session is stuck in closed state
114
+ console.log(`Second request failed (expected without fix): ${err.code || err.message}`)
115
+ // This demonstrates the issue exists - session is stuck after GOAWAY
116
+ }
117
+
118
+ // Cleanup in correct order: clients first, then proxy, then server
119
+ await instance.close()
120
+ targetServer.close()
121
+
122
+ // Force exit after a short delay to ensure test completes
123
+ setTimeout(() => {
124
+ process.exit(0)
125
+ }, 100)
126
+ })
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const h2url = require('h2url')
4
- const t = require('tap')
4
+ const t = require('node:test')
5
5
  const Fastify = require('fastify')
6
6
  const From = require('..')
7
7
  const fs = require('node:fs')
@@ -17,14 +17,14 @@ t.test('http2 -> http2', async (t) => {
17
17
  https: certs
18
18
  })
19
19
 
20
- t.teardown(instance.close.bind(instance))
20
+ t.after(() => instance.close())
21
21
 
22
22
  const target = Fastify({
23
23
  http2: true
24
24
  })
25
25
 
26
26
  target.get('/', (_request, reply) => {
27
- t.pass('request proxied')
27
+ t.assert.ok('request proxied')
28
28
  reply.code(404).header('x-my-header', 'hello!').send({
29
29
  hello: 'world'
30
30
  })
@@ -34,7 +34,7 @@ t.test('http2 -> http2', async (t) => {
34
34
  reply.from()
35
35
  })
36
36
 
37
- t.teardown(target.close.bind(target))
37
+ t.after(() => target.close())
38
38
 
39
39
  await target.listen({ port: 0 })
40
40
 
@@ -50,10 +50,10 @@ t.test('http2 -> http2', async (t) => {
50
50
  url: `https://localhost:${instance.server.address().port}`
51
51
  })
52
52
 
53
- t.equal(headers[':status'], 404)
54
- t.equal(headers['x-my-header'], 'hello!')
55
- t.match(headers['content-type'], /application\/json/)
56
- t.same(JSON.parse(body), { hello: 'world' })
53
+ t.assert.strictEqual(headers[':status'], 404)
54
+ t.assert.strictEqual(headers['x-my-header'], 'hello!')
55
+ t.assert.match(headers['content-type'], /application\/json/)
56
+ t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
57
57
  instance.close()
58
58
  target.close()
59
59
  })
@@ -1,10 +1,11 @@
1
1
  'use strict'
2
2
 
3
3
  const h2url = require('h2url')
4
- const t = require('tap')
4
+ const t = require('node:test')
5
+ const assert = require('node:assert')
5
6
  const Fastify = require('fastify')
7
+ const { request, Agent } = require('undici')
6
8
  const From = require('..')
7
- const got = require('got')
8
9
  const fs = require('node:fs')
9
10
  const path = require('node:path')
10
11
  const certs = {
@@ -18,15 +19,12 @@ const instance = Fastify({
18
19
  https: certs
19
20
  })
20
21
 
21
- t.plan(4)
22
- t.teardown(instance.close.bind(instance))
23
-
24
22
  const target = Fastify({
25
23
  https: certs
26
24
  })
27
25
 
28
26
  target.get('/', (_request, reply) => {
29
- t.pass('request proxied')
27
+ assert.ok('request proxied')
30
28
  reply.code(404).header('x-my-header', 'hello!').send({
31
29
  hello: 'world'
32
30
  })
@@ -36,9 +34,7 @@ instance.get('/', (_request, reply) => {
36
34
  reply.from()
37
35
  })
38
36
 
39
- t.teardown(target.close.bind(target))
40
-
41
- async function run () {
37
+ async function run (t) {
42
38
  await target.listen({ port: 0 })
43
39
 
44
40
  instance.register(From, {
@@ -48,33 +44,39 @@ async function run () {
48
44
 
49
45
  await instance.listen({ port: 0 })
50
46
 
51
- t.test('http2 -> https', async (t) => {
47
+ await t.test('http2 -> https', async (t) => {
48
+ t.plan(4)
52
49
  const { headers, body } = await h2url.concat({
53
50
  url: `https://localhost:${instance.server.address().port}`
54
51
  })
55
52
 
56
- t.equal(headers[':status'], 404)
57
- t.equal(headers['x-my-header'], 'hello!')
58
- t.match(headers['content-type'], /application\/json/)
59
- t.same(JSON.parse(body), { hello: 'world' })
53
+ t.assert.strictEqual(headers[':status'], 404)
54
+ t.assert.strictEqual(headers['x-my-header'], 'hello!')
55
+ t.assert.match(headers['content-type'], /application\/json/)
56
+ t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
60
57
  })
61
58
 
62
- t.test('https -> https', async (t) => {
63
- try {
64
- await got(`https://localhost:${instance.server.address().port}`, {
65
- https: {
59
+ await t.test('https -> https', async (t) => {
60
+ t.plan(4)
61
+ const result = await request(`https://localhost:${instance.server.address().port}`, {
62
+ dispatcher: new Agent({
63
+ connect: {
66
64
  rejectUnauthorized: false
67
65
  }
68
66
  })
69
- } catch (err) {
70
- t.equal(err.response.statusCode, 404)
71
- t.equal(err.response.headers['x-my-header'], 'hello!')
72
- t.match(err.response.headers['content-type'], /application\/json/)
73
- t.same(JSON.parse(err.response.body), { hello: 'world' })
74
- return
75
- }
76
- t.fail()
67
+ })
68
+
69
+ t.assert.strictEqual(result.statusCode, 404)
70
+ t.assert.strictEqual(result.headers['x-my-header'], 'hello!')
71
+ t.assert.match(result.headers['content-type'], /application\/json/)
72
+ t.assert.deepStrictEqual(await result.body.json(), { hello: 'world' })
77
73
  })
78
74
  }
79
75
 
80
- run()
76
+ t.test('http2 -> https', async (t) => {
77
+ t.plan(2)
78
+ t.after(() => instance.close())
79
+ t.after(() => target.close())
80
+
81
+ await run(t)
82
+ })
@@ -1,13 +1,13 @@
1
1
  'use strict'
2
2
 
3
- const { test } = require('tap')
3
+ const { test } = require('node:test')
4
4
  const Fastify = require('fastify')
5
5
  const From = require('../index')
6
6
 
7
7
  test('http2 invalid base', async (t) => {
8
8
  const instance = Fastify()
9
9
 
10
- await t.rejects(async () => instance.register(From, {
10
+ await t.assert.rejects(async () => instance.register(From, {
11
11
  http2: { requestTimeout: 100 }
12
12
  }), new Error('Option base is required when http2 is true'))
13
13
  })
@@ -1,14 +1,14 @@
1
1
  'use strict'
2
2
 
3
- const { test } = require('tap')
3
+ const { test } = require('node:test')
4
4
  const Fastify = require('fastify')
5
+ const { request } = require('undici')
5
6
  const From = require('..')
6
- const got = require('got')
7
7
 
8
8
  test('http2 invalid target', async (t) => {
9
9
  const instance = Fastify()
10
10
 
11
- t.teardown(instance.close.bind(instance))
11
+ t.after(() => instance.close())
12
12
 
13
13
  instance.get('/', (_request, reply) => {
14
14
  reply.from()
@@ -20,18 +20,14 @@ test('http2 invalid target', async (t) => {
20
20
 
21
21
  await instance.listen({ port: 0 })
22
22
 
23
- try {
24
- await got(`http://localhost:${instance.server.address().port}`)
25
- } catch (err) {
26
- t.equal(err.response.statusCode, 503)
27
- t.match(err.response.headers['content-type'], /application\/json/)
28
- t.same(JSON.parse(err.response.body), {
29
- statusCode: 503,
30
- code: 'FST_REPLY_FROM_SERVICE_UNAVAILABLE',
31
- error: 'Service Unavailable',
32
- message: 'Service Unavailable'
33
- })
34
- return
35
- }
36
- t.fail()
23
+ const result = await request(`http://localhost:${instance.server.address().port}`)
24
+
25
+ t.assert.strictEqual(result.statusCode, 503)
26
+ t.assert.match(result.headers['content-type'], /application\/json/)
27
+ t.assert.deepStrictEqual(await result.body.json(), {
28
+ statusCode: 503,
29
+ code: 'FST_REPLY_FROM_SERVICE_UNAVAILABLE',
30
+ error: 'Service Unavailable',
31
+ message: 'Service Unavailable'
32
+ })
37
33
  })
@@ -1,21 +1,21 @@
1
1
  'use strict'
2
2
 
3
- const { test } = require('tap')
3
+ const { test } = require('node:test')
4
4
  const Fastify = require('fastify')
5
+ const { request } = require('undici')
5
6
  const From = require('..')
6
- const got = require('got')
7
7
 
8
8
  test('http -> http2 crash', async (t) => {
9
9
  const instance = Fastify()
10
10
 
11
- t.teardown(instance.close.bind(instance))
11
+ t.after(() => instance.close())
12
12
 
13
13
  const target = Fastify({
14
14
  http2: true
15
15
  })
16
16
 
17
17
  target.get('/', (_request, reply) => {
18
- t.pass('request proxied')
18
+ t.assert.ok('request proxied')
19
19
  reply.code(200).send({
20
20
  hello: 'world'
21
21
  })
@@ -25,7 +25,7 @@ test('http -> http2 crash', async (t) => {
25
25
  reply.from()
26
26
  })
27
27
 
28
- t.teardown(target.close.bind(target))
28
+ t.after(() => target.close())
29
29
 
30
30
  await target.listen({ port: 0 })
31
31
 
@@ -36,19 +36,15 @@ test('http -> http2 crash', async (t) => {
36
36
 
37
37
  await instance.listen({ port: 0 })
38
38
 
39
- try {
40
- await target.close()
41
- await got(`http://localhost:${instance.server.address().port}`)
42
- } catch (err) {
43
- t.equal(err.response.statusCode, 503)
44
- t.match(err.response.headers['content-type'], /application\/json/)
45
- t.same(JSON.parse(err.response.body), {
46
- statusCode: 503,
47
- code: 'FST_REPLY_FROM_SERVICE_UNAVAILABLE',
48
- error: 'Service Unavailable',
49
- message: 'Service Unavailable'
50
- })
51
- return
52
- }
53
- t.fail()
39
+ await target.close()
40
+ const result = await request(`http://localhost:${instance.server.address().port}`)
41
+
42
+ t.assert.strictEqual(result.statusCode, 503)
43
+ t.assert.match(result.headers['content-type'], /application\/json/)
44
+ t.assert.deepStrictEqual(await result.body.json(), {
45
+ statusCode: 503,
46
+ code: 'FST_REPLY_FROM_SERVICE_UNAVAILABLE',
47
+ error: 'Service Unavailable',
48
+ message: 'Service Unavailable'
49
+ })
54
50
  })