node-fastify 5.8.3

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 (354) hide show
  1. package/.borp.yaml +3 -0
  2. package/.markdownlint-cli2.yaml +22 -0
  3. package/.prettierignore +1 -0
  4. package/GOVERNANCE.md +4 -0
  5. package/LICENSE +21 -0
  6. package/PROJECT_CHARTER.md +126 -0
  7. package/README.md +423 -0
  8. package/SECURITY.md +220 -0
  9. package/SPONSORS.md +24 -0
  10. package/build/build-error-serializer.js +35 -0
  11. package/build/build-validation.js +169 -0
  12. package/build/sync-version.js +11 -0
  13. package/docs/Guides/Benchmarking.md +60 -0
  14. package/docs/Guides/Database.md +321 -0
  15. package/docs/Guides/Delay-Accepting-Requests.md +608 -0
  16. package/docs/Guides/Detecting-When-Clients-Abort.md +172 -0
  17. package/docs/Guides/Ecosystem.md +726 -0
  18. package/docs/Guides/Fluent-Schema.md +127 -0
  19. package/docs/Guides/Getting-Started.md +620 -0
  20. package/docs/Guides/Index.md +43 -0
  21. package/docs/Guides/Migration-Guide-V3.md +287 -0
  22. package/docs/Guides/Migration-Guide-V4.md +267 -0
  23. package/docs/Guides/Migration-Guide-V5.md +727 -0
  24. package/docs/Guides/Plugins-Guide.md +520 -0
  25. package/docs/Guides/Prototype-Poisoning.md +383 -0
  26. package/docs/Guides/Recommendations.md +378 -0
  27. package/docs/Guides/Serverless.md +604 -0
  28. package/docs/Guides/Style-Guide.md +246 -0
  29. package/docs/Guides/Testing.md +481 -0
  30. package/docs/Guides/Write-Plugin.md +103 -0
  31. package/docs/Guides/Write-Type-Provider.md +34 -0
  32. package/docs/Reference/ContentTypeParser.md +271 -0
  33. package/docs/Reference/Decorators.md +436 -0
  34. package/docs/Reference/Encapsulation.md +194 -0
  35. package/docs/Reference/Errors.md +377 -0
  36. package/docs/Reference/HTTP2.md +94 -0
  37. package/docs/Reference/Hooks.md +958 -0
  38. package/docs/Reference/Index.md +73 -0
  39. package/docs/Reference/LTS.md +86 -0
  40. package/docs/Reference/Lifecycle.md +99 -0
  41. package/docs/Reference/Logging.md +268 -0
  42. package/docs/Reference/Middleware.md +79 -0
  43. package/docs/Reference/Plugins.md +245 -0
  44. package/docs/Reference/Principles.md +73 -0
  45. package/docs/Reference/Reply.md +1001 -0
  46. package/docs/Reference/Request.md +295 -0
  47. package/docs/Reference/Routes.md +802 -0
  48. package/docs/Reference/Server.md +2389 -0
  49. package/docs/Reference/Type-Providers.md +256 -0
  50. package/docs/Reference/TypeScript.md +1729 -0
  51. package/docs/Reference/Validation-and-Serialization.md +1130 -0
  52. package/docs/Reference/Warnings.md +58 -0
  53. package/docs/index.md +24 -0
  54. package/docs/resources/encapsulation_context.drawio +1 -0
  55. package/docs/resources/encapsulation_context.svg +3 -0
  56. package/eslint.config.js +35 -0
  57. package/examples/asyncawait.js +38 -0
  58. package/examples/benchmark/body.json +3 -0
  59. package/examples/benchmark/hooks-benchmark-async-await.js +44 -0
  60. package/examples/benchmark/hooks-benchmark.js +52 -0
  61. package/examples/benchmark/parser.js +47 -0
  62. package/examples/benchmark/simple.js +30 -0
  63. package/examples/benchmark/webstream.js +27 -0
  64. package/examples/hooks.js +91 -0
  65. package/examples/http2.js +39 -0
  66. package/examples/https.js +38 -0
  67. package/examples/parser.js +53 -0
  68. package/examples/plugin.js +12 -0
  69. package/examples/route-prefix.js +38 -0
  70. package/examples/shared-schema.js +38 -0
  71. package/examples/simple-stream.js +20 -0
  72. package/examples/simple.js +32 -0
  73. package/examples/simple.mjs +27 -0
  74. package/examples/typescript-server.ts +79 -0
  75. package/examples/use-plugin.js +29 -0
  76. package/fastify.d.ts +253 -0
  77. package/fastify.js +985 -0
  78. package/integration/server.js +29 -0
  79. package/integration/test.sh +23 -0
  80. package/lib/config-validator.js +1266 -0
  81. package/lib/content-type-parser.js +413 -0
  82. package/lib/content-type.js +160 -0
  83. package/lib/context.js +98 -0
  84. package/lib/decorate.js +152 -0
  85. package/lib/error-handler.js +173 -0
  86. package/lib/error-serializer.js +134 -0
  87. package/lib/error-status.js +14 -0
  88. package/lib/errors.js +516 -0
  89. package/lib/four-oh-four.js +190 -0
  90. package/lib/handle-request.js +195 -0
  91. package/lib/head-route.js +45 -0
  92. package/lib/hooks.js +429 -0
  93. package/lib/initial-config-validation.js +37 -0
  94. package/lib/logger-factory.js +136 -0
  95. package/lib/logger-pino.js +68 -0
  96. package/lib/noop-set.js +10 -0
  97. package/lib/plugin-override.js +90 -0
  98. package/lib/plugin-utils.js +169 -0
  99. package/lib/promise.js +23 -0
  100. package/lib/reply.js +1030 -0
  101. package/lib/req-id-gen-factory.js +52 -0
  102. package/lib/request.js +391 -0
  103. package/lib/route.js +686 -0
  104. package/lib/schema-controller.js +164 -0
  105. package/lib/schemas.js +207 -0
  106. package/lib/server.js +441 -0
  107. package/lib/symbols.js +71 -0
  108. package/lib/validation.js +280 -0
  109. package/lib/warnings.js +57 -0
  110. package/lib/wrap-thenable.js +84 -0
  111. package/package.json +225 -0
  112. package/scripts/validate-ecosystem-links.js +179 -0
  113. package/test/404s.test.js +2035 -0
  114. package/test/500s.test.js +422 -0
  115. package/test/allow-unsafe-regex.test.js +92 -0
  116. package/test/als.test.js +65 -0
  117. package/test/async-await.test.js +705 -0
  118. package/test/async-dispose.test.js +20 -0
  119. package/test/async_hooks.test.js +52 -0
  120. package/test/body-limit.test.js +224 -0
  121. package/test/buffer.test.js +74 -0
  122. package/test/build/error-serializer.test.js +36 -0
  123. package/test/build/version.test.js +14 -0
  124. package/test/build-certificate.js +109 -0
  125. package/test/bundler/README.md +29 -0
  126. package/test/bundler/esbuild/bundler-test.js +32 -0
  127. package/test/bundler/esbuild/package.json +10 -0
  128. package/test/bundler/esbuild/src/fail-plugin-version.js +14 -0
  129. package/test/bundler/esbuild/src/index.js +9 -0
  130. package/test/bundler/webpack/bundler-test.js +32 -0
  131. package/test/bundler/webpack/package.json +11 -0
  132. package/test/bundler/webpack/src/fail-plugin-version.js +14 -0
  133. package/test/bundler/webpack/src/index.js +9 -0
  134. package/test/bundler/webpack/webpack.config.js +15 -0
  135. package/test/case-insensitive.test.js +102 -0
  136. package/test/chainable.test.js +40 -0
  137. package/test/child-logger-factory.test.js +128 -0
  138. package/test/client-timeout.test.js +38 -0
  139. package/test/close-pipelining.test.js +78 -0
  140. package/test/close.test.js +706 -0
  141. package/test/conditional-pino.test.js +47 -0
  142. package/test/connection-timeout.test.js +42 -0
  143. package/test/constrained-routes.test.js +1138 -0
  144. package/test/content-length.test.js +174 -0
  145. package/test/content-parser.test.js +739 -0
  146. package/test/content-type.test.js +181 -0
  147. package/test/context-config.test.js +164 -0
  148. package/test/custom-http-server.test.js +118 -0
  149. package/test/custom-parser-async.test.js +59 -0
  150. package/test/custom-parser.0.test.js +701 -0
  151. package/test/custom-parser.1.test.js +266 -0
  152. package/test/custom-parser.2.test.js +91 -0
  153. package/test/custom-parser.3.test.js +208 -0
  154. package/test/custom-parser.4.test.js +218 -0
  155. package/test/custom-parser.5.test.js +130 -0
  156. package/test/custom-querystring-parser.test.js +129 -0
  157. package/test/decorator.test.js +1330 -0
  158. package/test/delete.test.js +344 -0
  159. package/test/diagnostics-channel/404.test.js +49 -0
  160. package/test/diagnostics-channel/async-delay-request.test.js +65 -0
  161. package/test/diagnostics-channel/async-request.test.js +64 -0
  162. package/test/diagnostics-channel/error-before-handler.test.js +35 -0
  163. package/test/diagnostics-channel/error-request.test.js +53 -0
  164. package/test/diagnostics-channel/error-status.test.js +123 -0
  165. package/test/diagnostics-channel/init.test.js +50 -0
  166. package/test/diagnostics-channel/sync-delay-request.test.js +49 -0
  167. package/test/diagnostics-channel/sync-request-reply.test.js +51 -0
  168. package/test/diagnostics-channel/sync-request.test.js +54 -0
  169. package/test/encapsulated-child-logger-factory.test.js +69 -0
  170. package/test/encapsulated-error-handler.test.js +237 -0
  171. package/test/esm/errorCodes.test.mjs +10 -0
  172. package/test/esm/esm.test.mjs +13 -0
  173. package/test/esm/index.test.js +8 -0
  174. package/test/esm/named-exports.mjs +14 -0
  175. package/test/esm/other.mjs +8 -0
  176. package/test/esm/plugin.mjs +8 -0
  177. package/test/fastify-instance.test.js +300 -0
  178. package/test/find-route.test.js +152 -0
  179. package/test/fluent-schema.test.js +209 -0
  180. package/test/genReqId.test.js +426 -0
  181. package/test/handler-context.test.js +45 -0
  182. package/test/handler-timeout.test.js +367 -0
  183. package/test/has-route.test.js +88 -0
  184. package/test/header-overflow.test.js +55 -0
  185. package/test/helper.js +496 -0
  186. package/test/hooks-async.test.js +1099 -0
  187. package/test/hooks.on-listen.test.js +1162 -0
  188. package/test/hooks.on-ready.test.js +421 -0
  189. package/test/hooks.test.js +3578 -0
  190. package/test/http-methods/copy.test.js +35 -0
  191. package/test/http-methods/custom-http-methods.test.js +114 -0
  192. package/test/http-methods/get.test.js +412 -0
  193. package/test/http-methods/head.test.js +263 -0
  194. package/test/http-methods/lock.test.js +108 -0
  195. package/test/http-methods/mkcalendar.test.js +143 -0
  196. package/test/http-methods/mkcol.test.js +35 -0
  197. package/test/http-methods/move.test.js +42 -0
  198. package/test/http-methods/propfind.test.js +136 -0
  199. package/test/http-methods/proppatch.test.js +105 -0
  200. package/test/http-methods/report.test.js +142 -0
  201. package/test/http-methods/search.test.js +233 -0
  202. package/test/http-methods/trace.test.js +21 -0
  203. package/test/http-methods/unlock.test.js +38 -0
  204. package/test/http2/closing.test.js +270 -0
  205. package/test/http2/constraint.test.js +109 -0
  206. package/test/http2/head.test.js +34 -0
  207. package/test/http2/plain.test.js +68 -0
  208. package/test/http2/secure-with-fallback.test.js +113 -0
  209. package/test/http2/secure.test.js +67 -0
  210. package/test/http2/unknown-http-method.test.js +34 -0
  211. package/test/https/custom-https-server.test.js +58 -0
  212. package/test/https/https.test.js +136 -0
  213. package/test/imports.test.js +17 -0
  214. package/test/inject.test.js +502 -0
  215. package/test/input-validation.js +335 -0
  216. package/test/internals/all.test.js +38 -0
  217. package/test/internals/content-type-parser.test.js +111 -0
  218. package/test/internals/context.test.js +31 -0
  219. package/test/internals/decorator.test.js +156 -0
  220. package/test/internals/errors.test.js +982 -0
  221. package/test/internals/handle-request.test.js +270 -0
  222. package/test/internals/hook-runner.test.js +449 -0
  223. package/test/internals/hooks.test.js +96 -0
  224. package/test/internals/initial-config.test.js +383 -0
  225. package/test/internals/logger.test.js +163 -0
  226. package/test/internals/plugin.test.js +170 -0
  227. package/test/internals/promise.test.js +63 -0
  228. package/test/internals/reply-serialize.test.js +714 -0
  229. package/test/internals/reply.test.js +1920 -0
  230. package/test/internals/req-id-gen-factory.test.js +133 -0
  231. package/test/internals/request-validate.test.js +1402 -0
  232. package/test/internals/request.test.js +506 -0
  233. package/test/internals/schema-controller-perf.test.js +40 -0
  234. package/test/internals/server.test.js +91 -0
  235. package/test/internals/validation.test.js +352 -0
  236. package/test/issue-4959.test.js +118 -0
  237. package/test/keep-alive-timeout.test.js +42 -0
  238. package/test/listen.1.test.js +154 -0
  239. package/test/listen.2.test.js +113 -0
  240. package/test/listen.3.test.js +83 -0
  241. package/test/listen.4.test.js +168 -0
  242. package/test/listen.5.test.js +122 -0
  243. package/test/logger/instantiation.test.js +341 -0
  244. package/test/logger/logger-test-utils.js +47 -0
  245. package/test/logger/logging.test.js +460 -0
  246. package/test/logger/options.test.js +579 -0
  247. package/test/logger/request.test.js +292 -0
  248. package/test/logger/response.test.js +183 -0
  249. package/test/logger/tap-parallel-not-ok +0 -0
  250. package/test/max-requests-per-socket.test.js +113 -0
  251. package/test/middleware.test.js +37 -0
  252. package/test/noop-set.test.js +19 -0
  253. package/test/nullable-validation.test.js +187 -0
  254. package/test/options.error-handler.test.js +5 -0
  255. package/test/options.test.js +5 -0
  256. package/test/output-validation.test.js +140 -0
  257. package/test/patch.error-handler.test.js +5 -0
  258. package/test/patch.test.js +5 -0
  259. package/test/plugin.1.test.js +230 -0
  260. package/test/plugin.2.test.js +314 -0
  261. package/test/plugin.3.test.js +287 -0
  262. package/test/plugin.4.test.js +504 -0
  263. package/test/plugin.helper.js +8 -0
  264. package/test/plugin.name.display.js +10 -0
  265. package/test/post-empty-body.test.js +38 -0
  266. package/test/pretty-print.test.js +366 -0
  267. package/test/promises.test.js +125 -0
  268. package/test/proto-poisoning.test.js +145 -0
  269. package/test/put.error-handler.test.js +5 -0
  270. package/test/put.test.js +5 -0
  271. package/test/register.test.js +184 -0
  272. package/test/reply-code.test.js +148 -0
  273. package/test/reply-early-hints.test.js +100 -0
  274. package/test/reply-error.test.js +815 -0
  275. package/test/reply-trailers.test.js +445 -0
  276. package/test/reply-web-stream-locked.test.js +37 -0
  277. package/test/request-error.test.js +624 -0
  278. package/test/request-header-host.test.js +339 -0
  279. package/test/request-id.test.js +118 -0
  280. package/test/request-timeout.test.js +53 -0
  281. package/test/route-hooks.test.js +635 -0
  282. package/test/route-prefix.test.js +904 -0
  283. package/test/route-shorthand.test.js +48 -0
  284. package/test/route.1.test.js +259 -0
  285. package/test/route.2.test.js +100 -0
  286. package/test/route.3.test.js +213 -0
  287. package/test/route.4.test.js +127 -0
  288. package/test/route.5.test.js +211 -0
  289. package/test/route.6.test.js +306 -0
  290. package/test/route.7.test.js +406 -0
  291. package/test/route.8.test.js +225 -0
  292. package/test/router-options.test.js +1108 -0
  293. package/test/same-shape.test.js +124 -0
  294. package/test/schema-examples.test.js +661 -0
  295. package/test/schema-feature.test.js +2198 -0
  296. package/test/schema-serialization.test.js +1171 -0
  297. package/test/schema-special-usage.test.js +1348 -0
  298. package/test/schema-validation.test.js +1572 -0
  299. package/test/scripts/validate-ecosystem-links.test.js +339 -0
  300. package/test/serialize-response.test.js +186 -0
  301. package/test/server.test.js +347 -0
  302. package/test/set-error-handler.test.js +69 -0
  303. package/test/skip-reply-send.test.js +317 -0
  304. package/test/stream-serializers.test.js +40 -0
  305. package/test/stream.1.test.js +94 -0
  306. package/test/stream.2.test.js +129 -0
  307. package/test/stream.3.test.js +198 -0
  308. package/test/stream.4.test.js +176 -0
  309. package/test/stream.5.test.js +188 -0
  310. package/test/sync-routes.test.js +32 -0
  311. package/test/throw.test.js +359 -0
  312. package/test/toolkit.js +63 -0
  313. package/test/trust-proxy.test.js +162 -0
  314. package/test/type-provider.test.js +22 -0
  315. package/test/types/content-type-parser.test-d.ts +72 -0
  316. package/test/types/decorate-request-reply.test-d.ts +18 -0
  317. package/test/types/dummy-plugin.ts +9 -0
  318. package/test/types/errors.test-d.ts +90 -0
  319. package/test/types/fastify.test-d.ts +352 -0
  320. package/test/types/hooks.test-d.ts +550 -0
  321. package/test/types/import.ts +2 -0
  322. package/test/types/instance.test-d.ts +588 -0
  323. package/test/types/logger.test-d.ts +277 -0
  324. package/test/types/plugin.test-d.ts +97 -0
  325. package/test/types/register.test-d.ts +237 -0
  326. package/test/types/reply.test-d.ts +254 -0
  327. package/test/types/request.test-d.ts +188 -0
  328. package/test/types/route.test-d.ts +553 -0
  329. package/test/types/schema.test-d.ts +135 -0
  330. package/test/types/serverFactory.test-d.ts +37 -0
  331. package/test/types/type-provider.test-d.ts +1213 -0
  332. package/test/types/using.test-d.ts +17 -0
  333. package/test/upgrade.test.js +52 -0
  334. package/test/url-rewriting.test.js +122 -0
  335. package/test/use-semicolon-delimiter.test.js +168 -0
  336. package/test/validation-error-handling.test.js +900 -0
  337. package/test/versioned-routes.test.js +603 -0
  338. package/test/web-api.test.js +616 -0
  339. package/test/wrap-thenable.test.js +30 -0
  340. package/types/content-type-parser.d.ts +75 -0
  341. package/types/context.d.ts +22 -0
  342. package/types/errors.d.ts +92 -0
  343. package/types/hooks.d.ts +875 -0
  344. package/types/instance.d.ts +609 -0
  345. package/types/logger.d.ts +107 -0
  346. package/types/plugin.d.ts +44 -0
  347. package/types/register.d.ts +42 -0
  348. package/types/reply.d.ts +81 -0
  349. package/types/request.d.ts +95 -0
  350. package/types/route.d.ts +199 -0
  351. package/types/schema.d.ts +61 -0
  352. package/types/server-factory.d.ts +19 -0
  353. package/types/type-provider.d.ts +130 -0
  354. package/types/utils.d.ts +98 -0
@@ -0,0 +1,3578 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('node:test')
4
+ const stream = require('node:stream')
5
+ const Fastify = require('..')
6
+ const fp = require('fastify-plugin')
7
+ const fs = require('node:fs')
8
+ const split = require('split2')
9
+ const symbols = require('../lib/symbols.js')
10
+ const payload = { hello: 'world' }
11
+ const proxyquire = require('proxyquire')
12
+ const { connect } = require('node:net')
13
+ const { sleep } = require('./helper')
14
+ const { waitForCb } = require('./toolkit.js')
15
+
16
+ process.removeAllListeners('warning')
17
+
18
+ test('hooks', async t => {
19
+ t.plan(48)
20
+ const fastify = Fastify({ exposeHeadRoutes: false })
21
+
22
+ try {
23
+ fastify.addHook('preHandler', function (request, reply, done) {
24
+ t.assert.strictEqual(request.test, 'the request is coming')
25
+ t.assert.strictEqual(reply.test, 'the reply has come')
26
+ if (request.raw.method === 'HEAD') {
27
+ done(new Error('some error'))
28
+ } else {
29
+ done()
30
+ }
31
+ })
32
+ t.assert.ok('should pass')
33
+ } catch (e) {
34
+ t.assert.fail()
35
+ }
36
+
37
+ try {
38
+ fastify.addHook('preHandler', null)
39
+ } catch (e) {
40
+ t.assert.strictEqual(e.code, 'FST_ERR_HOOK_INVALID_HANDLER')
41
+ t.assert.strictEqual(e.message, 'preHandler hook should be a function, instead got null')
42
+ t.assert.ok('should pass')
43
+ }
44
+
45
+ try {
46
+ fastify.addHook('preParsing')
47
+ } catch (e) {
48
+ t.assert.strictEqual(e.code, 'FST_ERR_HOOK_INVALID_HANDLER')
49
+ t.assert.strictEqual(e.message, 'preParsing hook should be a function, instead got undefined')
50
+ t.assert.ok('should pass')
51
+ }
52
+
53
+ try {
54
+ fastify.addHook('preParsing', function (request, reply, payload, done) {
55
+ request.preParsing = true
56
+ t.assert.strictEqual(request.test, 'the request is coming')
57
+ t.assert.strictEqual(reply.test, 'the reply has come')
58
+ done()
59
+ })
60
+ t.assert.ok('should pass')
61
+ } catch (e) {
62
+ t.assert.fail()
63
+ }
64
+
65
+ try {
66
+ fastify.addHook('preParsing', function (request, reply, payload, done) {
67
+ request.preParsing = true
68
+ t.assert.strictEqual(request.test, 'the request is coming')
69
+ t.assert.strictEqual(reply.test, 'the reply has come')
70
+ done()
71
+ })
72
+ t.assert.ok('should pass')
73
+ } catch (e) {
74
+ t.assert.fail()
75
+ }
76
+
77
+ try {
78
+ fastify.addHook('preValidation', function (request, reply, done) {
79
+ t.assert.strictEqual(request.preParsing, true)
80
+ t.assert.strictEqual(request.test, 'the request is coming')
81
+ t.assert.strictEqual(reply.test, 'the reply has come')
82
+ done()
83
+ })
84
+ t.assert.ok('should pass')
85
+ } catch (e) {
86
+ t.assert.fail()
87
+ }
88
+
89
+ try {
90
+ fastify.addHook('preSerialization', function (request, reply, payload, done) {
91
+ t.assert.ok('preSerialization called')
92
+ done()
93
+ })
94
+ t.assert.ok('should pass')
95
+ } catch (e) {
96
+ t.assert.fail()
97
+ }
98
+
99
+ try {
100
+ fastify.addHook('onRequest', function (request, reply, done) {
101
+ request.test = 'the request is coming'
102
+ reply.test = 'the reply has come'
103
+ if (request.raw.method === 'DELETE') {
104
+ done(new Error('some error'))
105
+ } else {
106
+ done()
107
+ }
108
+ })
109
+ t.assert.ok('should pass')
110
+ } catch (e) {
111
+ t.assert.fail()
112
+ }
113
+
114
+ fastify.addHook('onResponse', function (request, reply, done) {
115
+ t.assert.ok('onResponse called')
116
+ done()
117
+ })
118
+
119
+ fastify.addHook('onSend', function (req, reply, thePayload, done) {
120
+ t.assert.ok('onSend called')
121
+ done()
122
+ })
123
+
124
+ fastify.route({
125
+ method: 'GET',
126
+ url: '/',
127
+ handler: function (req, reply) {
128
+ t.assert.strictEqual(req.test, 'the request is coming')
129
+ t.assert.strictEqual(reply.test, 'the reply has come')
130
+ reply.code(200).send(payload)
131
+ },
132
+ onResponse: function (req, reply, done) {
133
+ t.assert.ok('onResponse inside hook')
134
+ },
135
+ response: {
136
+ 200: {
137
+ type: 'object'
138
+ }
139
+ }
140
+ })
141
+
142
+ fastify.head('/', function (req, reply) {
143
+ reply.code(200).send(payload)
144
+ })
145
+
146
+ fastify.delete('/', function (req, reply) {
147
+ reply.code(200).send(payload)
148
+ })
149
+
150
+ const fastifyServer = await fastify.listen({ port: 0 })
151
+ t.after(() => { fastify.close() })
152
+
153
+ const getResult = await fetch(fastifyServer)
154
+ t.assert.ok(getResult.ok)
155
+ t.assert.strictEqual(getResult.status, 200)
156
+ const getBody = await getResult.text()
157
+ t.assert.strictEqual(getResult.headers.get('content-length'), '' + getBody.length)
158
+ t.assert.deepStrictEqual(JSON.parse(getBody), { hello: 'world' })
159
+
160
+ const headResult = await fetch(fastifyServer, { method: 'HEAD' })
161
+ t.assert.ok(!headResult.ok)
162
+ t.assert.strictEqual(headResult.status, 500)
163
+
164
+ const deleteResult = await fetch(fastifyServer, { method: 'DELETE' })
165
+ t.assert.ok(!deleteResult.ok)
166
+ t.assert.strictEqual(deleteResult.status, 500)
167
+ })
168
+
169
+ test('onRequest hook should support encapsulation / 1', (t, testDone) => {
170
+ t.plan(5)
171
+ const fastify = Fastify()
172
+
173
+ fastify.register((instance, opts, done) => {
174
+ instance.addHook('onRequest', (req, reply, done) => {
175
+ t.assert.strictEqual(req.raw.url, '/plugin')
176
+ done()
177
+ })
178
+
179
+ instance.get('/plugin', (request, reply) => {
180
+ reply.send()
181
+ })
182
+
183
+ done()
184
+ })
185
+
186
+ fastify.get('/root', (request, reply) => {
187
+ reply.send()
188
+ })
189
+
190
+ fastify.inject('/root', (err, res) => {
191
+ t.assert.ifError(err)
192
+ t.assert.strictEqual(res.statusCode, 200)
193
+
194
+ fastify.inject('/plugin', (err, res) => {
195
+ t.assert.ifError(err)
196
+ t.assert.strictEqual(res.statusCode, 200)
197
+ testDone()
198
+ })
199
+ })
200
+ })
201
+
202
+ test('onRequest hook should support encapsulation / 2', (t, testDone) => {
203
+ t.plan(3)
204
+ const fastify = Fastify()
205
+ let pluginInstance
206
+
207
+ fastify.addHook('onRequest', () => { })
208
+
209
+ fastify.register((instance, opts, done) => {
210
+ instance.addHook('onRequest', () => { })
211
+ pluginInstance = instance
212
+ done()
213
+ })
214
+
215
+ fastify.ready(err => {
216
+ t.assert.ifError(err)
217
+ t.assert.strictEqual(fastify[symbols.kHooks].onRequest.length, 1)
218
+ t.assert.strictEqual(pluginInstance[symbols.kHooks].onRequest.length, 2)
219
+ testDone()
220
+ })
221
+ })
222
+
223
+ test('onRequest hook should support encapsulation / 3', async t => {
224
+ t.plan(19)
225
+ const fastify = Fastify()
226
+ fastify.decorate('hello', 'world')
227
+
228
+ fastify.addHook('onRequest', function (req, reply, done) {
229
+ t.assert.ok(this.hello)
230
+ t.assert.ok(this.hello2)
231
+ req.first = true
232
+ done()
233
+ })
234
+
235
+ fastify.decorate('hello2', 'world')
236
+
237
+ fastify.get('/first', (req, reply) => {
238
+ t.assert.ok(req.first)
239
+ t.assert.ok(!req.second)
240
+ reply.send({ hello: 'world' })
241
+ })
242
+
243
+ fastify.register((instance, opts, done) => {
244
+ instance.decorate('hello3', 'world')
245
+ instance.addHook('onRequest', function (req, reply, done) {
246
+ t.assert.ok(this.hello)
247
+ t.assert.ok(this.hello2)
248
+ t.assert.ok(this.hello3)
249
+ req.second = true
250
+ done()
251
+ })
252
+
253
+ instance.get('/second', (req, reply) => {
254
+ t.assert.ok(req.first)
255
+ t.assert.ok(req.second)
256
+ reply.send({ hello: 'world' })
257
+ })
258
+
259
+ done()
260
+ })
261
+
262
+ const fastifyServer = await fastify.listen({ port: 0 })
263
+ t.after(() => { fastify.close() })
264
+
265
+ const firstResult = await fetch(fastifyServer + '/first', { method: 'GET' })
266
+ t.assert.ok(firstResult.ok)
267
+ t.assert.strictEqual(firstResult.status, 200)
268
+ const firstBody = await firstResult.text()
269
+ t.assert.strictEqual(firstResult.headers.get('content-length'), '' + firstBody.length)
270
+ t.assert.deepStrictEqual(JSON.parse(firstBody), { hello: 'world' })
271
+
272
+ const secondResult = await fetch(fastifyServer + '/second', { method: 'GET' })
273
+ t.assert.ok(secondResult.ok)
274
+ t.assert.strictEqual(secondResult.status, 200)
275
+ const secondBody = await secondResult.text()
276
+ t.assert.strictEqual(secondResult.headers.get('content-length'), '' + secondBody.length)
277
+ t.assert.deepStrictEqual(JSON.parse(secondBody), { hello: 'world' })
278
+ })
279
+
280
+ test('preHandler hook should support encapsulation / 5', async t => {
281
+ t.plan(16)
282
+ const fastify = Fastify()
283
+ t.after(() => { fastify.close() })
284
+ fastify.decorate('hello', 'world')
285
+
286
+ fastify.addHook('preHandler', function (req, res, done) {
287
+ t.assert.ok(this.hello)
288
+ req.first = true
289
+ done()
290
+ })
291
+
292
+ fastify.get('/first', (req, reply) => {
293
+ t.assert.ok(req.first)
294
+ t.assert.ok(!req.second)
295
+ reply.send({ hello: 'world' })
296
+ })
297
+
298
+ fastify.register((instance, opts, done) => {
299
+ instance.decorate('hello2', 'world')
300
+ instance.addHook('preHandler', function (req, res, done) {
301
+ t.assert.ok(this.hello)
302
+ t.assert.ok(this.hello2)
303
+ req.second = true
304
+ done()
305
+ })
306
+
307
+ instance.get('/second', (req, reply) => {
308
+ t.assert.ok(req.first)
309
+ t.assert.ok(req.second)
310
+ reply.send({ hello: 'world' })
311
+ })
312
+
313
+ done()
314
+ })
315
+
316
+ const fastifyServer = await fastify.listen({ port: 0 })
317
+
318
+ const firstResult = await fetch(fastifyServer + '/first')
319
+ t.assert.ok(firstResult.ok)
320
+ t.assert.strictEqual(firstResult.status, 200)
321
+ const firstBody = await firstResult.text()
322
+ t.assert.strictEqual(firstResult.headers.get('content-length'), '' + firstBody.length)
323
+ t.assert.deepStrictEqual(JSON.parse(firstBody), { hello: 'world' })
324
+
325
+ const secondResult = await fetch(fastifyServer + '/second')
326
+ t.assert.ok(secondResult.ok)
327
+ t.assert.strictEqual(secondResult.status, 200)
328
+ const secondBody = await secondResult.text()
329
+ t.assert.strictEqual(secondResult.headers.get('content-length'), '' + secondBody.length)
330
+ t.assert.deepStrictEqual(JSON.parse(secondBody), { hello: 'world' })
331
+ })
332
+
333
+ test('onRoute hook should be called / 1', (t, testDone) => {
334
+ t.plan(2)
335
+ const fastify = Fastify({ exposeHeadRoutes: false })
336
+
337
+ fastify.register((instance, opts, done) => {
338
+ instance.addHook('onRoute', () => {
339
+ t.assert.ok('should pass')
340
+ })
341
+ instance.get('/', opts, function (req, reply) {
342
+ reply.send()
343
+ })
344
+ done()
345
+ })
346
+
347
+ fastify.ready(err => {
348
+ t.assert.ifError(err)
349
+ testDone()
350
+ })
351
+ })
352
+
353
+ test('onRoute hook should be called / 2', (t, testDone) => {
354
+ t.plan(5)
355
+ let firstHandler = 0
356
+ let secondHandler = 0
357
+ const fastify = Fastify({ exposeHeadRoutes: false })
358
+ fastify.addHook('onRoute', (route) => {
359
+ t.assert.ok('should pass')
360
+ firstHandler++
361
+ })
362
+
363
+ fastify.register((instance, opts, done) => {
364
+ instance.addHook('onRoute', (route) => {
365
+ t.assert.ok('should pass')
366
+ secondHandler++
367
+ })
368
+ instance.get('/', opts, function (req, reply) {
369
+ reply.send()
370
+ })
371
+ done()
372
+ })
373
+ .after(() => {
374
+ t.assert.strictEqual(firstHandler, 1)
375
+ t.assert.strictEqual(secondHandler, 1)
376
+ })
377
+
378
+ fastify.ready(err => {
379
+ t.assert.ifError(err)
380
+ testDone()
381
+ })
382
+ })
383
+
384
+ test('onRoute hook should be called / 3', (t, testDone) => {
385
+ t.plan(5)
386
+ const fastify = Fastify({ exposeHeadRoutes: false })
387
+
388
+ function handler (req, reply) {
389
+ reply.send()
390
+ }
391
+
392
+ fastify.addHook('onRoute', (route) => {
393
+ t.assert.ok('should pass')
394
+ })
395
+
396
+ fastify.register((instance, opts, done) => {
397
+ instance.addHook('onRoute', (route) => {
398
+ t.assert.ok('should pass')
399
+ })
400
+ instance.get('/a', handler)
401
+ done()
402
+ })
403
+ .after((err, done) => {
404
+ t.assert.ifError(err)
405
+ setTimeout(() => {
406
+ fastify.get('/b', handler)
407
+ done()
408
+ }, 10)
409
+ })
410
+
411
+ fastify.ready(err => {
412
+ t.assert.ifError(err)
413
+ testDone()
414
+ })
415
+ })
416
+
417
+ test('onRoute hook should be called (encapsulation support) / 4', (t, testDone) => {
418
+ t.plan(4)
419
+ const fastify = Fastify({ exposeHeadRoutes: false })
420
+
421
+ fastify.addHook('onRoute', () => {
422
+ t.assert.ok('should pass')
423
+ })
424
+
425
+ fastify.register((instance, opts, done) => {
426
+ instance.addHook('onRoute', () => {
427
+ t.assert.ok('should pass')
428
+ })
429
+ instance.get('/nested', opts, function (req, reply) {
430
+ reply.send()
431
+ })
432
+ done()
433
+ })
434
+
435
+ fastify.get('/', function (req, reply) {
436
+ reply.send()
437
+ })
438
+
439
+ fastify.ready(err => {
440
+ t.assert.ifError(err)
441
+ testDone()
442
+ })
443
+ })
444
+
445
+ test('onRoute hook should be called (encapsulation support) / 5', (t, testDone) => {
446
+ t.plan(2)
447
+ const fastify = Fastify({ exposeHeadRoutes: false })
448
+
449
+ fastify.get('/first', function (req, reply) {
450
+ reply.send()
451
+ })
452
+
453
+ fastify.register((instance, opts, done) => {
454
+ instance.addHook('onRoute', () => {
455
+ t.assert.ok('should pass')
456
+ })
457
+ instance.get('/nested', opts, function (req, reply) {
458
+ reply.send()
459
+ })
460
+ done()
461
+ })
462
+
463
+ fastify.get('/second', function (req, reply) {
464
+ reply.send()
465
+ })
466
+
467
+ fastify.ready(err => {
468
+ t.assert.ifError(err)
469
+ testDone()
470
+ })
471
+ })
472
+
473
+ test('onRoute hook should be called (encapsulation support) / 6', (t, testDone) => {
474
+ t.plan(1)
475
+ const fastify = Fastify({ exposeHeadRoutes: false })
476
+
477
+ fastify.get('/first', function (req, reply) {
478
+ reply.send()
479
+ })
480
+
481
+ fastify.addHook('onRoute', () => {
482
+ t.assert.fail('This should not be called')
483
+ })
484
+
485
+ fastify.ready(err => {
486
+ t.assert.ifError(err)
487
+ testDone()
488
+ })
489
+ })
490
+
491
+ test('onRoute should keep the context', (t, testDone) => {
492
+ t.plan(4)
493
+ const fastify = Fastify({ exposeHeadRoutes: false })
494
+ fastify.register((instance, opts, done) => {
495
+ instance.decorate('test', true)
496
+ instance.addHook('onRoute', onRoute)
497
+ t.assert.ok(instance.prototype === fastify.prototype)
498
+
499
+ function onRoute (route) {
500
+ t.assert.ok(this.test)
501
+ t.assert.strictEqual(this, instance)
502
+ }
503
+
504
+ instance.get('/', opts, function (req, reply) {
505
+ reply.send()
506
+ })
507
+
508
+ done()
509
+ })
510
+
511
+ fastify.close((err) => {
512
+ t.assert.ifError(err)
513
+ testDone()
514
+ })
515
+ })
516
+
517
+ test('onRoute hook should pass correct route', (t, testDone) => {
518
+ t.plan(9)
519
+ const fastify = Fastify({ exposeHeadRoutes: false })
520
+ fastify.addHook('onRoute', (route) => {
521
+ t.assert.strictEqual(route.method, 'GET')
522
+ t.assert.strictEqual(route.url, '/')
523
+ t.assert.strictEqual(route.path, '/')
524
+ t.assert.strictEqual(route.routePath, '/')
525
+ })
526
+
527
+ fastify.register((instance, opts, done) => {
528
+ instance.addHook('onRoute', (route) => {
529
+ t.assert.strictEqual(route.method, 'GET')
530
+ t.assert.strictEqual(route.url, '/')
531
+ t.assert.strictEqual(route.path, '/')
532
+ t.assert.strictEqual(route.routePath, '/')
533
+ })
534
+ instance.get('/', opts, function (req, reply) {
535
+ reply.send()
536
+ })
537
+ done()
538
+ })
539
+
540
+ fastify.ready(err => {
541
+ t.assert.ifError(err)
542
+ testDone()
543
+ })
544
+ })
545
+
546
+ test('onRoute hook should pass correct route with custom prefix', (t, testDone) => {
547
+ t.plan(11)
548
+ const fastify = Fastify({ exposeHeadRoutes: false })
549
+ fastify.addHook('onRoute', function (route) {
550
+ t.assert.strictEqual(route.method, 'GET')
551
+ t.assert.strictEqual(route.url, '/v1/foo')
552
+ t.assert.strictEqual(route.path, '/v1/foo')
553
+ t.assert.strictEqual(route.routePath, '/foo')
554
+ t.assert.strictEqual(route.prefix, '/v1')
555
+ })
556
+
557
+ fastify.register((instance, opts, done) => {
558
+ instance.addHook('onRoute', function (route) {
559
+ t.assert.strictEqual(route.method, 'GET')
560
+ t.assert.strictEqual(route.url, '/v1/foo')
561
+ t.assert.strictEqual(route.path, '/v1/foo')
562
+ t.assert.strictEqual(route.routePath, '/foo')
563
+ t.assert.strictEqual(route.prefix, '/v1')
564
+ })
565
+ instance.get('/foo', opts, function (req, reply) {
566
+ reply.send()
567
+ })
568
+ done()
569
+ }, { prefix: '/v1' })
570
+
571
+ fastify.ready(err => {
572
+ t.assert.ifError(err)
573
+ testDone()
574
+ })
575
+ })
576
+
577
+ test('onRoute hook should pass correct route with custom options', (t, testDone) => {
578
+ t.plan(6)
579
+ const fastify = Fastify({ exposeHeadRoutes: false })
580
+ fastify.register((instance, opts, done) => {
581
+ instance.addHook('onRoute', function (route) {
582
+ t.assert.strictEqual(route.method, 'GET')
583
+ t.assert.strictEqual(route.url, '/foo')
584
+ t.assert.strictEqual(route.logLevel, 'info')
585
+ t.assert.strictEqual(route.bodyLimit, 100)
586
+ t.assert.ok(typeof route.logSerializers.test === 'function')
587
+ })
588
+ instance.get('/foo', {
589
+ logLevel: 'info',
590
+ bodyLimit: 100,
591
+ logSerializers: {
592
+ test: value => value
593
+ }
594
+ }, function (req, reply) {
595
+ reply.send()
596
+ })
597
+ done()
598
+ })
599
+
600
+ fastify.ready(err => {
601
+ t.assert.ifError(err)
602
+ testDone()
603
+ })
604
+ })
605
+
606
+ test('onRoute hook should receive any route option', (t, testDone) => {
607
+ t.plan(5)
608
+ const fastify = Fastify({ exposeHeadRoutes: false })
609
+ fastify.register((instance, opts, done) => {
610
+ instance.addHook('onRoute', function (route) {
611
+ t.assert.strictEqual(route.method, 'GET')
612
+ t.assert.strictEqual(route.url, '/foo')
613
+ t.assert.strictEqual(route.routePath, '/foo')
614
+ t.assert.strictEqual(route.auth, 'basic')
615
+ })
616
+ instance.get('/foo', { auth: 'basic' }, function (req, reply) {
617
+ reply.send()
618
+ })
619
+ done()
620
+ })
621
+
622
+ fastify.ready(err => {
623
+ t.assert.ifError(err)
624
+ testDone()
625
+ })
626
+ })
627
+
628
+ test('onRoute hook should preserve system route configuration', (t, testDone) => {
629
+ t.plan(5)
630
+ const fastify = Fastify({ exposeHeadRoutes: false })
631
+ fastify.register((instance, opts, done) => {
632
+ instance.addHook('onRoute', function (route) {
633
+ t.assert.strictEqual(route.method, 'GET')
634
+ t.assert.strictEqual(route.url, '/foo')
635
+ t.assert.strictEqual(route.routePath, '/foo')
636
+ t.assert.strictEqual(route.handler.length, 2)
637
+ })
638
+ instance.get('/foo', { url: '/bar', method: 'POST' }, function (req, reply) {
639
+ reply.send()
640
+ })
641
+ done()
642
+ })
643
+
644
+ fastify.ready(err => {
645
+ t.assert.ifError(err)
646
+ testDone()
647
+ })
648
+ })
649
+
650
+ test('onRoute hook should preserve handler function in options of shorthand route system configuration', (t, testDone) => {
651
+ t.plan(2)
652
+
653
+ const handler = (req, reply) => { }
654
+
655
+ const fastify = Fastify({ exposeHeadRoutes: false })
656
+ fastify.register((instance, opts, done) => {
657
+ instance.addHook('onRoute', function (route) {
658
+ t.assert.strictEqual(route.handler, handler)
659
+ })
660
+ instance.get('/foo', { handler })
661
+ done()
662
+ })
663
+
664
+ fastify.ready(err => {
665
+ t.assert.ifError(err)
666
+ testDone()
667
+ })
668
+ })
669
+
670
+ // issue ref https://github.com/fastify/fastify-compress/issues/140
671
+ test('onRoute hook should be called once when prefixTrailingSlash', (t, testDone) => {
672
+ t.plan(3)
673
+
674
+ let onRouteCalled = 0
675
+ let routePatched = 0
676
+
677
+ const fastify = Fastify({ ignoreTrailingSlash: false, exposeHeadRoutes: false })
678
+
679
+ // a plugin that patches route options, similar to fastify-compress
680
+ fastify.register(fp(function myPlugin (instance, opts, next) {
681
+ function patchTheRoute () {
682
+ routePatched++
683
+ }
684
+
685
+ instance.addHook('onRoute', function (routeOptions) {
686
+ onRouteCalled++
687
+ patchTheRoute(routeOptions)
688
+ })
689
+
690
+ next()
691
+ }))
692
+
693
+ fastify.register(function routes (instance, opts, next) {
694
+ instance.route({
695
+ method: 'GET',
696
+ url: '/',
697
+ prefixTrailingSlash: 'both',
698
+ handler: (req, reply) => {
699
+ reply.send({ hello: 'world' })
700
+ }
701
+ })
702
+
703
+ next()
704
+ }, { prefix: '/prefix' })
705
+
706
+ fastify.ready(err => {
707
+ t.assert.ifError(err)
708
+ t.assert.strictEqual(onRouteCalled, 1) // onRoute hook was called once
709
+ t.assert.strictEqual(routePatched, 1) // and plugin acted once and avoided redundant route patching
710
+ testDone()
711
+ })
712
+ })
713
+
714
+ test('onRoute hook should able to change the route url', async t => {
715
+ t.plan(4)
716
+
717
+ const fastify = Fastify({ exposeHeadRoutes: false })
718
+ t.after(() => { fastify.close() })
719
+
720
+ fastify.register((instance, opts, done) => {
721
+ instance.addHook('onRoute', (route) => {
722
+ t.assert.strictEqual(route.url, '/foo')
723
+ route.url = encodeURI(route.url)
724
+ })
725
+
726
+ instance.get('/foo', (request, reply) => {
727
+ reply.send('here /foo')
728
+ })
729
+
730
+ done()
731
+ })
732
+
733
+ const fastifyServer = await fastify.listen({ port: 0 })
734
+
735
+ const result = await fetch(fastifyServer + encodeURI('/foo'))
736
+ t.assert.ok(result.ok)
737
+ t.assert.strictEqual(result.status, 200)
738
+ t.assert.strictEqual(await result.text(), 'here /foo')
739
+ })
740
+
741
+ test('onRoute hook that throws should be caught', (t, testDone) => {
742
+ t.plan(1)
743
+ const fastify = Fastify({ exposeHeadRoutes: false })
744
+
745
+ fastify.register((instance, opts, done) => {
746
+ instance.addHook('onRoute', () => {
747
+ throw new Error('snap')
748
+ })
749
+
750
+ try {
751
+ instance.get('/', opts, function (req, reply) {
752
+ reply.send()
753
+ })
754
+
755
+ t.assert.fail('onRoute should throw sync if error')
756
+ } catch (error) {
757
+ t.assert.ok(error)
758
+ }
759
+
760
+ done()
761
+ })
762
+
763
+ fastify.ready(testDone)
764
+ })
765
+
766
+ test('onRoute hook with many prefix', (t, testDone) => {
767
+ t.plan(3)
768
+ const fastify = Fastify({ exposeHeadRoutes: false })
769
+ const handler = (req, reply) => { reply.send({}) }
770
+
771
+ const onRouteChecks = [
772
+ { routePath: '/anotherPath', prefix: '/one/two', url: '/one/two/anotherPath' },
773
+ { routePath: '/aPath', prefix: '/one', url: '/one/aPath' }
774
+ ]
775
+
776
+ fastify.register((instance, opts, done) => {
777
+ instance.addHook('onRoute', ({ routePath, prefix, url }) => {
778
+ t.assert.deepStrictEqual({ routePath, prefix, url }, onRouteChecks.pop())
779
+ })
780
+ instance.route({ method: 'GET', url: '/aPath', handler })
781
+
782
+ instance.register((instance, opts, done) => {
783
+ instance.route({ method: 'GET', path: '/anotherPath', handler })
784
+ done()
785
+ }, { prefix: '/two' })
786
+ done()
787
+ }, { prefix: '/one' })
788
+
789
+ fastify.ready(err => {
790
+ t.assert.ifError(err)
791
+ testDone()
792
+ })
793
+ })
794
+
795
+ test('onRoute hook should not be called when it registered after route', (t, testDone) => {
796
+ t.plan(3)
797
+ const fastify = Fastify()
798
+
799
+ fastify.addHook('onRoute', () => {
800
+ t.assert.ok('should pass')
801
+ })
802
+
803
+ fastify.get('/', function (req, reply) {
804
+ reply.send()
805
+ })
806
+
807
+ fastify.addHook('onRoute', () => {
808
+ t.assert.fail('should not be called')
809
+ })
810
+
811
+ fastify.ready(err => {
812
+ t.assert.ifError(err)
813
+ testDone()
814
+ })
815
+ })
816
+
817
+ test('onResponse hook should log request error', (t, testDone) => {
818
+ t.plan(4)
819
+
820
+ let fastify = null
821
+ const logStream = split(JSON.parse)
822
+ try {
823
+ fastify = Fastify({
824
+ logger: {
825
+ stream: logStream,
826
+ level: 'error'
827
+ }
828
+ })
829
+ } catch (e) {
830
+ t.assert.fail()
831
+ }
832
+
833
+ logStream.once('data', line => {
834
+ t.assert.strictEqual(line.msg, 'request errored')
835
+ t.assert.strictEqual(line.level, 50)
836
+ })
837
+
838
+ fastify.addHook('onResponse', (request, reply, done) => {
839
+ done(new Error('kaboom'))
840
+ })
841
+
842
+ fastify.get('/root', (request, reply) => {
843
+ reply.send()
844
+ })
845
+
846
+ fastify.inject('/root', (err, res) => {
847
+ t.assert.ifError(err)
848
+ t.assert.strictEqual(res.statusCode, 200)
849
+ testDone()
850
+ })
851
+ })
852
+
853
+ test('onResponse hook should support encapsulation / 1', (t, testDone) => {
854
+ t.plan(5)
855
+ const fastify = Fastify()
856
+
857
+ fastify.register((instance, opts, done) => {
858
+ instance.addHook('onResponse', (request, reply, done) => {
859
+ t.assert.strictEqual(reply.plugin, true)
860
+ done()
861
+ })
862
+
863
+ instance.get('/plugin', (request, reply) => {
864
+ reply.plugin = true
865
+ reply.send()
866
+ })
867
+
868
+ done()
869
+ })
870
+
871
+ fastify.get('/root', (request, reply) => {
872
+ reply.send()
873
+ })
874
+
875
+ fastify.inject('/root', (err, res) => {
876
+ t.assert.ifError(err)
877
+ t.assert.strictEqual(res.statusCode, 200)
878
+ })
879
+
880
+ fastify.inject('/plugin', (err, res) => {
881
+ t.assert.ifError(err)
882
+ t.assert.strictEqual(res.statusCode, 200)
883
+ testDone()
884
+ })
885
+ })
886
+
887
+ test('onResponse hook should support encapsulation / 2', (t, testDone) => {
888
+ t.plan(3)
889
+ const fastify = Fastify()
890
+ let pluginInstance
891
+
892
+ fastify.addHook('onResponse', () => { })
893
+
894
+ fastify.register((instance, opts, done) => {
895
+ instance.addHook('onResponse', () => { })
896
+ pluginInstance = instance
897
+ done()
898
+ })
899
+
900
+ fastify.ready(err => {
901
+ t.assert.ifError(err)
902
+ t.assert.strictEqual(fastify[symbols.kHooks].onResponse.length, 1)
903
+ t.assert.strictEqual(pluginInstance[symbols.kHooks].onResponse.length, 2)
904
+ testDone()
905
+ })
906
+ })
907
+
908
+ test('onResponse hook should support encapsulation / 3', async t => {
909
+ t.plan(15)
910
+ const fastify = Fastify()
911
+ t.after(() => { fastify.close() })
912
+ fastify.decorate('hello', 'world')
913
+
914
+ fastify.addHook('onResponse', function (request, reply, done) {
915
+ t.assert.ok(this.hello)
916
+ t.assert.ok('onResponse called')
917
+ done()
918
+ })
919
+
920
+ fastify.get('/first', (req, reply) => {
921
+ reply.send({ hello: 'world' })
922
+ })
923
+
924
+ fastify.register((instance, opts, done) => {
925
+ instance.decorate('hello2', 'world')
926
+ instance.addHook('onResponse', function (request, reply, done) {
927
+ t.assert.ok(this.hello)
928
+ t.assert.ok(this.hello2)
929
+ t.assert.ok('onResponse called')
930
+ done()
931
+ })
932
+
933
+ instance.get('/second', (req, reply) => {
934
+ reply.send({ hello: 'world' })
935
+ })
936
+
937
+ done()
938
+ })
939
+
940
+ const fastifyServer = await fastify.listen({ port: 0 })
941
+
942
+ const firstResult = await fetch(fastifyServer + '/first', { method: 'GET' })
943
+ t.assert.ok(firstResult.ok)
944
+ t.assert.strictEqual(firstResult.status, 200)
945
+ const firstBody = await firstResult.text()
946
+ t.assert.strictEqual(firstResult.headers.get('content-length'), '' + firstBody.length)
947
+ t.assert.deepStrictEqual(JSON.parse(firstBody), { hello: 'world' })
948
+
949
+ const secondResult = await fetch(fastifyServer + '/second')
950
+ t.assert.ok(secondResult.ok)
951
+ t.assert.strictEqual(secondResult.status, 200)
952
+ const secondBody = await secondResult.text()
953
+ t.assert.strictEqual(secondResult.headers.get('content-length'), '' + secondBody.length)
954
+ t.assert.deepStrictEqual(JSON.parse(secondBody), { hello: 'world' })
955
+ })
956
+
957
+ test('onSend hook should support encapsulation / 1', (t, testDone) => {
958
+ t.plan(3)
959
+ const fastify = Fastify()
960
+ let pluginInstance
961
+
962
+ fastify.addHook('onSend', () => { })
963
+
964
+ fastify.register((instance, opts, done) => {
965
+ instance.addHook('onSend', () => { })
966
+ pluginInstance = instance
967
+ done()
968
+ })
969
+
970
+ fastify.ready(err => {
971
+ t.assert.ifError(err)
972
+ t.assert.strictEqual(fastify[symbols.kHooks].onSend.length, 1)
973
+ t.assert.strictEqual(pluginInstance[symbols.kHooks].onSend.length, 2)
974
+ testDone()
975
+ })
976
+ })
977
+
978
+ test('onSend hook should support encapsulation / 2', async t => {
979
+ t.plan(15)
980
+ const fastify = Fastify()
981
+ t.after(() => { fastify.close() })
982
+ fastify.decorate('hello', 'world')
983
+
984
+ fastify.addHook('onSend', function (request, reply, thePayload, done) {
985
+ t.assert.ok(this.hello)
986
+ t.assert.ok('onSend called')
987
+ done()
988
+ })
989
+
990
+ fastify.get('/first', (req, reply) => {
991
+ reply.send({ hello: 'world' })
992
+ })
993
+
994
+ fastify.register((instance, opts, done) => {
995
+ instance.decorate('hello2', 'world')
996
+ instance.addHook('onSend', function (request, reply, thePayload, done) {
997
+ t.assert.ok(this.hello)
998
+ t.assert.ok(this.hello2)
999
+ t.assert.ok('onSend called')
1000
+ done()
1001
+ })
1002
+
1003
+ instance.get('/second', (req, reply) => {
1004
+ reply.send({ hello: 'world' })
1005
+ })
1006
+
1007
+ done()
1008
+ })
1009
+
1010
+ const fastifyServer = await fastify.listen({ port: 0 })
1011
+
1012
+ const firstResult = await fetch(fastifyServer + '/first')
1013
+ t.assert.ok(firstResult.ok)
1014
+ t.assert.strictEqual(firstResult.status, 200)
1015
+ const firstBody = await firstResult.text()
1016
+ t.assert.strictEqual(firstResult.headers.get('content-length'), '' + firstBody.length)
1017
+ t.assert.deepStrictEqual(JSON.parse(firstBody), { hello: 'world' })
1018
+
1019
+ const secondResult = await fetch(fastifyServer + '/second')
1020
+ t.assert.ok(secondResult.ok)
1021
+ t.assert.strictEqual(secondResult.status, 200)
1022
+ const secondBody = await secondResult.text()
1023
+ t.assert.strictEqual(secondResult.headers.get('content-length'), '' + secondBody.length)
1024
+ t.assert.deepStrictEqual(JSON.parse(secondBody), { hello: 'world' })
1025
+ })
1026
+
1027
+ test('onSend hook is called after payload is serialized and headers are set', (t, testDone) => {
1028
+ t.plan(30)
1029
+ const fastify = Fastify()
1030
+
1031
+ fastify.register((instance, opts, done) => {
1032
+ const thePayload = { hello: 'world' }
1033
+
1034
+ instance.addHook('onSend', function (request, reply, payload, done) {
1035
+ t.assert.deepStrictEqual(JSON.parse(payload), thePayload)
1036
+ t.assert.strictEqual(reply[symbols.kReplyHeaders]['content-type'], 'application/json; charset=utf-8')
1037
+ done()
1038
+ })
1039
+
1040
+ instance.get('/json', (request, reply) => {
1041
+ reply.send(thePayload)
1042
+ })
1043
+
1044
+ done()
1045
+ })
1046
+
1047
+ fastify.register((instance, opts, done) => {
1048
+ instance.addHook('onSend', function (request, reply, payload, done) {
1049
+ t.assert.strictEqual(payload, 'some text')
1050
+ t.assert.strictEqual(reply[symbols.kReplyHeaders]['content-type'], 'text/plain; charset=utf-8')
1051
+ done()
1052
+ })
1053
+
1054
+ instance.get('/text', (request, reply) => {
1055
+ reply.send('some text')
1056
+ })
1057
+
1058
+ done()
1059
+ })
1060
+
1061
+ fastify.register((instance, opts, done) => {
1062
+ const thePayload = Buffer.from('buffer payload')
1063
+
1064
+ instance.addHook('onSend', function (request, reply, payload, done) {
1065
+ t.assert.strictEqual(payload, thePayload)
1066
+ t.assert.strictEqual(reply[symbols.kReplyHeaders]['content-type'], 'application/octet-stream')
1067
+ done()
1068
+ })
1069
+
1070
+ instance.get('/buffer', (request, reply) => {
1071
+ reply.send(thePayload)
1072
+ })
1073
+
1074
+ done()
1075
+ })
1076
+
1077
+ fastify.register((instance, opts, done) => {
1078
+ let chunk = 'stream payload'
1079
+ const thePayload = new stream.Readable({
1080
+ read () {
1081
+ this.push(chunk)
1082
+ chunk = null
1083
+ }
1084
+ })
1085
+
1086
+ instance.addHook('onSend', function (request, reply, payload, done) {
1087
+ t.assert.strictEqual(payload, thePayload)
1088
+ t.assert.strictEqual(reply[symbols.kReplyHeaders]['content-type'], 'application/octet-stream')
1089
+ done()
1090
+ })
1091
+
1092
+ instance.get('/stream', (request, reply) => {
1093
+ reply.header('content-type', 'application/octet-stream')
1094
+ reply.send(thePayload)
1095
+ })
1096
+
1097
+ done()
1098
+ })
1099
+
1100
+ fastify.register((instance, opts, done) => {
1101
+ const serializedPayload = 'serialized'
1102
+
1103
+ instance.addHook('onSend', function (request, reply, payload, done) {
1104
+ t.assert.strictEqual(payload, serializedPayload)
1105
+ t.assert.strictEqual(reply[symbols.kReplyHeaders]['content-type'], 'text/custom')
1106
+ done()
1107
+ })
1108
+
1109
+ instance.get('/custom-serializer', (request, reply) => {
1110
+ reply
1111
+ .serializer(() => serializedPayload)
1112
+ .type('text/custom')
1113
+ .send('needs to be serialized')
1114
+ })
1115
+
1116
+ done()
1117
+ })
1118
+
1119
+ const completion = waitForCb({ steps: 5 })
1120
+ fastify.inject({
1121
+ method: 'GET',
1122
+ url: '/json'
1123
+ }, (err, res) => {
1124
+ t.assert.ifError(err)
1125
+ t.assert.strictEqual(res.statusCode, 200)
1126
+ t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'world' })
1127
+ t.assert.strictEqual(res.headers['content-length'], '17')
1128
+ completion.stepIn()
1129
+ })
1130
+
1131
+ fastify.inject({
1132
+ method: 'GET',
1133
+ url: '/text'
1134
+ }, (err, res) => {
1135
+ t.assert.ifError(err)
1136
+ t.assert.strictEqual(res.statusCode, 200)
1137
+ t.assert.deepStrictEqual(res.payload, 'some text')
1138
+ t.assert.strictEqual(res.headers['content-length'], '9')
1139
+ completion.stepIn()
1140
+ })
1141
+
1142
+ fastify.inject({
1143
+ method: 'GET',
1144
+ url: '/buffer'
1145
+ }, (err, res) => {
1146
+ t.assert.ifError(err)
1147
+ t.assert.strictEqual(res.statusCode, 200)
1148
+ t.assert.deepStrictEqual(res.payload, 'buffer payload')
1149
+ t.assert.strictEqual(res.headers['content-length'], '14')
1150
+ completion.stepIn()
1151
+ })
1152
+
1153
+ fastify.inject({
1154
+ method: 'GET',
1155
+ url: '/stream'
1156
+ }, (err, res) => {
1157
+ t.assert.ifError(err)
1158
+ t.assert.strictEqual(res.statusCode, 200)
1159
+ t.assert.deepStrictEqual(res.payload, 'stream payload')
1160
+ t.assert.strictEqual(res.headers['transfer-encoding'], 'chunked')
1161
+ completion.stepIn()
1162
+ })
1163
+
1164
+ fastify.inject({
1165
+ method: 'GET',
1166
+ url: '/custom-serializer'
1167
+ }, (err, res) => {
1168
+ t.assert.ifError(err)
1169
+ t.assert.strictEqual(res.statusCode, 200)
1170
+ t.assert.deepStrictEqual(res.payload, 'serialized')
1171
+ t.assert.strictEqual(res.headers['content-type'], 'text/custom')
1172
+ completion.stepIn()
1173
+ })
1174
+ completion.patience.then(testDone)
1175
+ })
1176
+
1177
+ test('modify payload', (t, testDone) => {
1178
+ t.plan(10)
1179
+ const fastify = Fastify()
1180
+ const payload = { hello: 'world' }
1181
+ const modifiedPayload = { hello: 'modified' }
1182
+ const anotherPayload = '"winter is coming"'
1183
+
1184
+ fastify.addHook('onSend', function (request, reply, thePayload, done) {
1185
+ t.assert.ok('onSend called')
1186
+ t.assert.deepStrictEqual(JSON.parse(thePayload), payload)
1187
+ thePayload = thePayload.replace('world', 'modified')
1188
+ done(null, thePayload)
1189
+ })
1190
+
1191
+ fastify.addHook('onSend', function (request, reply, thePayload, done) {
1192
+ t.assert.ok('onSend called')
1193
+ t.assert.deepStrictEqual(JSON.parse(thePayload), modifiedPayload)
1194
+ done(null, anotherPayload)
1195
+ })
1196
+
1197
+ fastify.addHook('onSend', function (request, reply, thePayload, done) {
1198
+ t.assert.ok('onSend called')
1199
+ t.assert.strictEqual(thePayload, anotherPayload)
1200
+ done()
1201
+ })
1202
+
1203
+ fastify.get('/', (req, reply) => {
1204
+ reply.send(payload)
1205
+ })
1206
+
1207
+ fastify.inject({
1208
+ method: 'GET',
1209
+ url: '/'
1210
+ }, (err, res) => {
1211
+ t.assert.ifError(err)
1212
+ t.assert.strictEqual(res.payload, anotherPayload)
1213
+ t.assert.strictEqual(res.statusCode, 200)
1214
+ t.assert.strictEqual(res.headers['content-length'], '18')
1215
+ testDone()
1216
+ })
1217
+ })
1218
+
1219
+ test('clear payload', (t, testDone) => {
1220
+ t.plan(6)
1221
+ const fastify = Fastify()
1222
+
1223
+ fastify.addHook('onSend', function (request, reply, payload, done) {
1224
+ t.assert.ok('onSend called')
1225
+ reply.code(304)
1226
+ done(null, null)
1227
+ })
1228
+
1229
+ fastify.get('/', (req, reply) => {
1230
+ reply.send({ hello: 'world' })
1231
+ })
1232
+
1233
+ fastify.inject({
1234
+ method: 'GET',
1235
+ url: '/'
1236
+ }, (err, res) => {
1237
+ t.assert.ifError(err)
1238
+ t.assert.strictEqual(res.statusCode, 304)
1239
+ t.assert.strictEqual(res.payload, '')
1240
+ t.assert.strictEqual(res.headers['content-length'], undefined)
1241
+ t.assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8')
1242
+ testDone()
1243
+ })
1244
+ })
1245
+
1246
+ test('onSend hook throws', async t => {
1247
+ t.plan(10)
1248
+ const Fastify = proxyquire('..', {
1249
+ './lib/schemas.js': {
1250
+ getSchemaSerializer: (param1, param2, param3) => {
1251
+ t.assert.strictEqual(param3, 'application/json; charset=utf-8', 'param3 should be "application/json; charset=utf-8"')
1252
+ }
1253
+ }
1254
+ })
1255
+ const fastify = Fastify()
1256
+ t.after(() => { fastify.close() })
1257
+ fastify.addHook('onSend', function (request, reply, payload, done) {
1258
+ if (request.raw.method === 'DELETE') {
1259
+ done(new Error('some error'))
1260
+ return
1261
+ }
1262
+
1263
+ if (request.raw.method === 'PUT') {
1264
+ throw new Error('some error')
1265
+ }
1266
+
1267
+ if (request.raw.method === 'POST') {
1268
+ throw new Error('some error')
1269
+ }
1270
+
1271
+ done()
1272
+ })
1273
+
1274
+ fastify.get('/', (req, reply) => {
1275
+ reply.send({ hello: 'world' })
1276
+ })
1277
+
1278
+ fastify.post('/', {
1279
+ schema: {
1280
+ response: {
1281
+ 200: {
1282
+ content: {
1283
+ 'application/json': {
1284
+ schema: {
1285
+ name: { type: 'string' },
1286
+ image: { type: 'string' },
1287
+ address: { type: 'string' }
1288
+ }
1289
+ }
1290
+ }
1291
+ }
1292
+ }
1293
+ }
1294
+ }, (req, reply) => {
1295
+ reply.send({ hello: 'world' })
1296
+ })
1297
+
1298
+ fastify.delete('/', (req, reply) => {
1299
+ reply.send({ hello: 'world' })
1300
+ })
1301
+
1302
+ fastify.put('/', (req, reply) => {
1303
+ reply.send({ hello: 'world' })
1304
+ })
1305
+
1306
+ const fastifyServer = await fastify.listen({ port: 0 })
1307
+
1308
+ const getResult = await fetch(fastifyServer)
1309
+ t.assert.ok(getResult.ok)
1310
+ t.assert.strictEqual(getResult.status, 200)
1311
+ const getBody = await getResult.text()
1312
+ t.assert.strictEqual(getResult.headers.get('content-length'), '' + getBody.length)
1313
+ t.assert.deepStrictEqual(JSON.parse(getBody), { hello: 'world' })
1314
+
1315
+ const postResult = await fetch(fastifyServer, { method: 'POST' })
1316
+ t.assert.ok(!postResult.ok)
1317
+ t.assert.strictEqual(postResult.status, 500)
1318
+
1319
+ const deleteResult = await fetch(fastifyServer, { method: 'DELETE' })
1320
+ t.assert.ok(!deleteResult.ok)
1321
+ t.assert.strictEqual(deleteResult.status, 500)
1322
+
1323
+ const putResult = await fetch(fastifyServer, { method: 'PUT' })
1324
+ t.assert.ok(!putResult.ok)
1325
+ t.assert.strictEqual(putResult.status, 500)
1326
+ })
1327
+
1328
+ test('onSend hook should receive valid request and reply objects if onRequest hook fails', (t, testDone) => {
1329
+ t.plan(4)
1330
+ const fastify = Fastify()
1331
+
1332
+ fastify.decorateRequest('testDecorator', 'testDecoratorVal')
1333
+ fastify.decorateReply('testDecorator', 'testDecoratorVal')
1334
+
1335
+ fastify.addHook('onRequest', function (req, reply, done) {
1336
+ done(new Error('onRequest hook failed'))
1337
+ })
1338
+
1339
+ fastify.addHook('onSend', function (request, reply, payload, done) {
1340
+ t.assert.strictEqual(request.testDecorator, 'testDecoratorVal')
1341
+ t.assert.strictEqual(reply.testDecorator, 'testDecoratorVal')
1342
+ done()
1343
+ })
1344
+
1345
+ fastify.get('/', (req, reply) => {
1346
+ reply.send('hello')
1347
+ })
1348
+
1349
+ fastify.inject({
1350
+ method: 'GET',
1351
+ url: '/'
1352
+ }, (err, res) => {
1353
+ t.assert.ifError(err)
1354
+ t.assert.strictEqual(res.statusCode, 500)
1355
+ testDone()
1356
+ })
1357
+ })
1358
+
1359
+ test('onSend hook should receive valid request and reply objects if a custom content type parser fails', (t, testDone) => {
1360
+ t.plan(4)
1361
+ const fastify = Fastify()
1362
+
1363
+ fastify.decorateRequest('testDecorator', 'testDecoratorVal')
1364
+ fastify.decorateReply('testDecorator', 'testDecoratorVal')
1365
+
1366
+ fastify.addContentTypeParser('*', function (req, payload, done) {
1367
+ done(new Error('content type parser failed'))
1368
+ })
1369
+
1370
+ fastify.addHook('onSend', function (request, reply, payload, done) {
1371
+ t.assert.strictEqual(request.testDecorator, 'testDecoratorVal')
1372
+ t.assert.strictEqual(reply.testDecorator, 'testDecoratorVal')
1373
+ done()
1374
+ })
1375
+
1376
+ fastify.get('/', (req, reply) => {
1377
+ reply.send('hello')
1378
+ })
1379
+
1380
+ fastify.inject({
1381
+ method: 'POST',
1382
+ url: '/',
1383
+ payload: 'body'
1384
+ }, (err, res) => {
1385
+ t.assert.ifError(err)
1386
+ t.assert.strictEqual(res.statusCode, 500)
1387
+ testDone()
1388
+ })
1389
+ })
1390
+
1391
+ test('Content-Length header should be updated if onSend hook modifies the payload', (t, testDone) => {
1392
+ t.plan(2)
1393
+
1394
+ const instance = Fastify()
1395
+
1396
+ instance.get('/', async (_, rep) => {
1397
+ rep.header('content-length', 3)
1398
+ return 'foo'
1399
+ })
1400
+
1401
+ instance.addHook('onSend', async () => 'bar12233000')
1402
+
1403
+ instance.inject({
1404
+ method: 'GET',
1405
+ url: '/'
1406
+ }, (err, res) => {
1407
+ t.assert.ifError(err)
1408
+ const payloadLength = Buffer.byteLength(res.body)
1409
+ const contentLength = Number(res.headers['content-length'])
1410
+
1411
+ t.assert.strictEqual(payloadLength, contentLength)
1412
+ testDone()
1413
+ })
1414
+ })
1415
+
1416
+ test('cannot add hook after binding', (t, testDone) => {
1417
+ t.plan(1)
1418
+ const instance = Fastify()
1419
+ t.after(() => instance.close())
1420
+
1421
+ instance.get('/', function (request, reply) {
1422
+ reply.send({ hello: 'world' })
1423
+ })
1424
+
1425
+ instance.listen({ port: 0 }, err => {
1426
+ t.assert.ifError(err)
1427
+
1428
+ try {
1429
+ instance.addHook('onRequest', () => { })
1430
+ t.assert.fail()
1431
+ } catch (e) {
1432
+ testDone()
1433
+ }
1434
+ })
1435
+ })
1436
+
1437
+ test('onRequest hooks should be able to block a request', (t, testDone) => {
1438
+ t.plan(5)
1439
+ const fastify = Fastify()
1440
+
1441
+ fastify.addHook('onRequest', (req, reply, done) => {
1442
+ reply.send('hello')
1443
+ done()
1444
+ })
1445
+
1446
+ fastify.addHook('onRequest', (req, reply, done) => {
1447
+ t.assert.fail('this should not be called')
1448
+ })
1449
+
1450
+ fastify.addHook('preHandler', (req, reply, done) => {
1451
+ t.assert.fail('this should not be called')
1452
+ })
1453
+
1454
+ fastify.addHook('onSend', (req, reply, payload, done) => {
1455
+ t.assert.ok('called')
1456
+ done()
1457
+ })
1458
+
1459
+ fastify.addHook('onResponse', (request, reply, done) => {
1460
+ t.assert.ok('called')
1461
+ done()
1462
+ })
1463
+
1464
+ fastify.get('/', function (request, reply) {
1465
+ t.assert.fail('we should not be here')
1466
+ })
1467
+
1468
+ fastify.inject({
1469
+ url: '/',
1470
+ method: 'GET'
1471
+ }, (err, res) => {
1472
+ t.assert.ifError(err)
1473
+ t.assert.strictEqual(res.statusCode, 200)
1474
+ t.assert.strictEqual(res.payload, 'hello')
1475
+ testDone()
1476
+ })
1477
+ })
1478
+
1479
+ test('preValidation hooks should be able to block a request', (t, testDone) => {
1480
+ t.plan(5)
1481
+ const fastify = Fastify()
1482
+
1483
+ fastify.addHook('preValidation', (req, reply, done) => {
1484
+ reply.send('hello')
1485
+ done()
1486
+ })
1487
+
1488
+ fastify.addHook('preValidation', (req, reply, done) => {
1489
+ t.assert.fail('this should not be called')
1490
+ })
1491
+
1492
+ fastify.addHook('preHandler', (req, reply, done) => {
1493
+ t.assert.fail('this should not be called')
1494
+ })
1495
+
1496
+ fastify.addHook('onSend', (req, reply, payload, done) => {
1497
+ t.assert.ok('called')
1498
+ done()
1499
+ })
1500
+
1501
+ fastify.addHook('onResponse', (request, reply, done) => {
1502
+ t.assert.ok('called')
1503
+ done()
1504
+ })
1505
+
1506
+ fastify.get('/', function (request, reply) {
1507
+ t.assert.fail('we should not be here')
1508
+ })
1509
+
1510
+ fastify.inject({
1511
+ url: '/',
1512
+ method: 'GET'
1513
+ }, (err, res) => {
1514
+ t.assert.ifError(err)
1515
+ t.assert.strictEqual(res.statusCode, 200)
1516
+ t.assert.strictEqual(res.payload, 'hello')
1517
+ testDone()
1518
+ })
1519
+ })
1520
+
1521
+ test('preValidation hooks should be able to change request body before validation', (t, testDone) => {
1522
+ t.plan(4)
1523
+ const fastify = Fastify()
1524
+
1525
+ fastify.addHook('preValidation', (req, _reply, done) => {
1526
+ const buff = Buffer.from(req.body.message, 'base64')
1527
+ req.body = JSON.parse(buff.toString('utf-8'))
1528
+ done()
1529
+ })
1530
+
1531
+ fastify.post(
1532
+ '/',
1533
+ {
1534
+ schema: {
1535
+ body: {
1536
+ type: 'object',
1537
+ properties: {
1538
+ foo: {
1539
+ type: 'string'
1540
+ },
1541
+ bar: {
1542
+ type: 'number'
1543
+ }
1544
+ },
1545
+ required: ['foo', 'bar']
1546
+ }
1547
+ }
1548
+ },
1549
+ (req, reply) => {
1550
+ t.assert.ok('should pass')
1551
+ reply.status(200).send('hello')
1552
+ }
1553
+ )
1554
+
1555
+ fastify.inject({
1556
+ url: '/',
1557
+ method: 'POST',
1558
+ payload: {
1559
+ message: Buffer.from(JSON.stringify({ foo: 'example', bar: 1 })).toString('base64')
1560
+ }
1561
+ }, (err, res) => {
1562
+ t.assert.ifError(err)
1563
+ t.assert.strictEqual(res.statusCode, 200)
1564
+ t.assert.strictEqual(res.payload, 'hello')
1565
+ testDone()
1566
+ })
1567
+ })
1568
+
1569
+ test('preParsing hooks should be able to block a request', (t, testDone) => {
1570
+ t.plan(5)
1571
+ const fastify = Fastify()
1572
+
1573
+ fastify.addHook('preParsing', (req, reply, payload, done) => {
1574
+ reply.send('hello')
1575
+ done()
1576
+ })
1577
+
1578
+ fastify.addHook('preParsing', (req, reply, payload, done) => {
1579
+ t.assert.fail('this should not be called')
1580
+ })
1581
+
1582
+ fastify.addHook('preHandler', (req, reply, done) => {
1583
+ t.assert.fail('this should not be called')
1584
+ })
1585
+
1586
+ fastify.addHook('onSend', (req, reply, payload, done) => {
1587
+ t.assert.ok('called')
1588
+ done()
1589
+ })
1590
+
1591
+ fastify.addHook('onResponse', (request, reply, done) => {
1592
+ t.assert.ok('called')
1593
+ done()
1594
+ })
1595
+
1596
+ fastify.get('/', function (request, reply) {
1597
+ t.assert.fail('we should not be here')
1598
+ })
1599
+
1600
+ fastify.inject({
1601
+ url: '/',
1602
+ method: 'GET'
1603
+ }, (err, res) => {
1604
+ t.assert.ifError(err)
1605
+ t.assert.strictEqual(res.statusCode, 200)
1606
+ t.assert.strictEqual(res.payload, 'hello')
1607
+ testDone()
1608
+ })
1609
+ })
1610
+
1611
+ test('preHandler hooks should be able to block a request', (t, testDone) => {
1612
+ t.plan(5)
1613
+ const fastify = Fastify()
1614
+
1615
+ fastify.addHook('preHandler', (req, reply, done) => {
1616
+ reply.send('hello')
1617
+ done()
1618
+ })
1619
+
1620
+ fastify.addHook('preHandler', (req, reply, done) => {
1621
+ t.assert.fail('this should not be called')
1622
+ })
1623
+
1624
+ fastify.addHook('onSend', (req, reply, payload, done) => {
1625
+ t.assert.strictEqual(payload, 'hello')
1626
+ done()
1627
+ })
1628
+
1629
+ fastify.addHook('onResponse', (request, reply, done) => {
1630
+ t.assert.ok('called')
1631
+ done()
1632
+ })
1633
+
1634
+ fastify.get('/', function (request, reply) {
1635
+ t.assert.fail('we should not be here')
1636
+ })
1637
+
1638
+ fastify.inject({
1639
+ url: '/',
1640
+ method: 'GET'
1641
+ }, (err, res) => {
1642
+ t.assert.ifError(err)
1643
+ t.assert.strictEqual(res.statusCode, 200)
1644
+ t.assert.strictEqual(res.payload, 'hello')
1645
+ testDone()
1646
+ })
1647
+ })
1648
+
1649
+ test('onRequest hooks should be able to block a request (last hook)', (t, testDone) => {
1650
+ t.plan(5)
1651
+ const fastify = Fastify()
1652
+
1653
+ fastify.addHook('onRequest', (req, reply, done) => {
1654
+ reply.send('hello')
1655
+ done()
1656
+ })
1657
+
1658
+ fastify.addHook('preHandler', (req, reply, done) => {
1659
+ t.assert.fail('this should not be called')
1660
+ })
1661
+
1662
+ fastify.addHook('onSend', (req, reply, payload, done) => {
1663
+ t.assert.ok('called')
1664
+ done()
1665
+ })
1666
+
1667
+ fastify.addHook('onResponse', (request, reply, done) => {
1668
+ t.assert.ok('called')
1669
+ done()
1670
+ })
1671
+
1672
+ fastify.get('/', function (request, reply) {
1673
+ t.assert.fail('we should not be here')
1674
+ })
1675
+
1676
+ fastify.inject({
1677
+ url: '/',
1678
+ method: 'GET'
1679
+ }, (err, res) => {
1680
+ t.assert.ifError(err)
1681
+ t.assert.strictEqual(res.statusCode, 200)
1682
+ t.assert.strictEqual(res.payload, 'hello')
1683
+ testDone()
1684
+ })
1685
+ })
1686
+
1687
+ test('preHandler hooks should be able to block a request (last hook)', (t, testDone) => {
1688
+ t.plan(5)
1689
+ const fastify = Fastify()
1690
+
1691
+ fastify.addHook('preHandler', (req, reply, done) => {
1692
+ reply.send('hello')
1693
+ done()
1694
+ })
1695
+
1696
+ fastify.addHook('onSend', (req, reply, payload, done) => {
1697
+ t.assert.strictEqual(payload, 'hello')
1698
+ done()
1699
+ })
1700
+
1701
+ fastify.addHook('onResponse', (request, reply, done) => {
1702
+ t.assert.ok('called')
1703
+ done()
1704
+ })
1705
+
1706
+ fastify.get('/', function (request, reply) {
1707
+ t.assert.fail('we should not be here')
1708
+ })
1709
+
1710
+ fastify.inject({
1711
+ url: '/',
1712
+ method: 'GET'
1713
+ }, (err, res) => {
1714
+ t.assert.ifError(err)
1715
+ t.assert.strictEqual(res.statusCode, 200)
1716
+ t.assert.strictEqual(res.payload, 'hello')
1717
+ testDone()
1718
+ })
1719
+ })
1720
+
1721
+ test('preParsing hooks should handle errors', (t, testDone) => {
1722
+ t.plan(3)
1723
+ const fastify = Fastify()
1724
+
1725
+ fastify.addHook('preParsing', (req, reply, payload, done) => {
1726
+ const e = new Error('kaboom')
1727
+ e.statusCode = 501
1728
+ throw e
1729
+ })
1730
+
1731
+ fastify.post('/', function (request, reply) {
1732
+ reply.send(request.body)
1733
+ })
1734
+
1735
+ fastify.inject({
1736
+ method: 'POST',
1737
+ url: '/',
1738
+ payload: { hello: 'world' }
1739
+ }, (err, res) => {
1740
+ t.assert.ifError(err)
1741
+ t.assert.strictEqual(res.statusCode, 501)
1742
+ t.assert.deepStrictEqual(JSON.parse(res.payload), { error: 'Not Implemented', message: 'kaboom', statusCode: 501 })
1743
+ testDone()
1744
+ })
1745
+ })
1746
+
1747
+ test('onRequest respond with a stream', (t, testDone) => {
1748
+ t.plan(4)
1749
+ const fastify = Fastify()
1750
+
1751
+ fastify.addHook('onRequest', (req, reply, done) => {
1752
+ const stream = fs.createReadStream(__filename, 'utf8')
1753
+ // stream.pipe(res)
1754
+ // res.once('finish', done)
1755
+ reply.send(stream)
1756
+ })
1757
+
1758
+ fastify.addHook('onRequest', (req, res, done) => {
1759
+ t.assert.fail('this should not be called')
1760
+ })
1761
+
1762
+ fastify.addHook('preHandler', (req, reply, done) => {
1763
+ t.assert.fail('this should not be called')
1764
+ })
1765
+
1766
+ fastify.addHook('onSend', (req, reply, payload, done) => {
1767
+ t.assert.ok('called')
1768
+ done()
1769
+ })
1770
+
1771
+ fastify.addHook('onResponse', (request, reply, done) => {
1772
+ t.assert.ok('called')
1773
+ done()
1774
+ })
1775
+
1776
+ fastify.get('/', function (request, reply) {
1777
+ t.assert.fail('we should not be here')
1778
+ })
1779
+
1780
+ fastify.inject({
1781
+ url: '/',
1782
+ method: 'GET'
1783
+ }, (err, res) => {
1784
+ t.assert.ifError(err)
1785
+ t.assert.strictEqual(res.statusCode, 200)
1786
+ testDone()
1787
+ })
1788
+ })
1789
+
1790
+ test('preHandler respond with a stream', (t, testDone) => {
1791
+ t.plan(7)
1792
+ const fastify = Fastify()
1793
+
1794
+ fastify.addHook('onRequest', (req, reply, done) => {
1795
+ t.assert.ok('called')
1796
+ done()
1797
+ })
1798
+
1799
+ // we are calling `reply.send` inside the `preHandler` hook with a stream,
1800
+ // this triggers the `onSend` hook event if `preHandler` has not yet finished
1801
+ const order = [1, 2]
1802
+
1803
+ fastify.addHook('preHandler', (req, reply, done) => {
1804
+ const stream = fs.createReadStream(__filename, 'utf8')
1805
+ reply.send(stream)
1806
+ reply.raw.once('finish', () => {
1807
+ t.assert.strictEqual(order.shift(), 2)
1808
+ done()
1809
+ })
1810
+ })
1811
+
1812
+ fastify.addHook('preHandler', (req, reply, done) => {
1813
+ t.assert.fail('this should not be called')
1814
+ })
1815
+
1816
+ fastify.addHook('onSend', (req, reply, payload, done) => {
1817
+ t.assert.strictEqual(order.shift(), 1)
1818
+ t.assert.strictEqual(typeof payload.pipe, 'function')
1819
+ done()
1820
+ })
1821
+
1822
+ fastify.addHook('onResponse', (request, reply, done) => {
1823
+ t.assert.ok('called')
1824
+ done()
1825
+ })
1826
+
1827
+ fastify.get('/', function (request, reply) {
1828
+ t.assert.fail('we should not be here')
1829
+ })
1830
+
1831
+ fastify.inject({
1832
+ url: '/',
1833
+ method: 'GET'
1834
+ }, (err, res) => {
1835
+ t.assert.ifError(err)
1836
+ t.assert.strictEqual(res.statusCode, 200)
1837
+ testDone()
1838
+ })
1839
+ })
1840
+
1841
+ test('Register an hook after a plugin inside a plugin', (t, testDone) => {
1842
+ t.plan(6)
1843
+ const fastify = Fastify()
1844
+
1845
+ fastify.register(fp(function (instance, opts, done) {
1846
+ instance.addHook('preHandler', function (req, reply, done) {
1847
+ t.assert.ok('called')
1848
+ done()
1849
+ })
1850
+
1851
+ instance.get('/', function (request, reply) {
1852
+ reply.send({ hello: 'world' })
1853
+ })
1854
+
1855
+ done()
1856
+ }))
1857
+
1858
+ fastify.register(fp(function (instance, opts, done) {
1859
+ instance.addHook('preHandler', function (req, reply, done) {
1860
+ t.assert.ok('called')
1861
+ done()
1862
+ })
1863
+
1864
+ instance.addHook('preHandler', function (req, reply, done) {
1865
+ t.assert.ok('called')
1866
+ done()
1867
+ })
1868
+
1869
+ done()
1870
+ }))
1871
+
1872
+ fastify.inject({
1873
+ url: '/',
1874
+ method: 'GET'
1875
+ }, (err, res) => {
1876
+ t.assert.ifError(err)
1877
+ t.assert.strictEqual(res.statusCode, 200)
1878
+ t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'world' })
1879
+ testDone()
1880
+ })
1881
+ })
1882
+
1883
+ test('Register an hook after a plugin inside a plugin (with preHandler option)', (t, testDone) => {
1884
+ t.plan(7)
1885
+ const fastify = Fastify()
1886
+
1887
+ fastify.register(fp(function (instance, opts, done) {
1888
+ instance.addHook('preHandler', function (req, reply, done) {
1889
+ t.assert.ok('called')
1890
+ done()
1891
+ })
1892
+
1893
+ instance.get('/', {
1894
+ preHandler: (req, reply, done) => {
1895
+ t.assert.ok('called')
1896
+ done()
1897
+ }
1898
+ }, function (request, reply) {
1899
+ reply.send({ hello: 'world' })
1900
+ })
1901
+
1902
+ done()
1903
+ }))
1904
+
1905
+ fastify.register(fp(function (instance, opts, done) {
1906
+ instance.addHook('preHandler', function (req, reply, done) {
1907
+ t.assert.ok('called')
1908
+ done()
1909
+ })
1910
+
1911
+ instance.addHook('preHandler', function (req, reply, done) {
1912
+ t.assert.ok('called')
1913
+ done()
1914
+ })
1915
+
1916
+ done()
1917
+ }))
1918
+
1919
+ fastify.inject({
1920
+ url: '/',
1921
+ method: 'GET'
1922
+ }, (err, res) => {
1923
+ t.assert.ifError(err)
1924
+ t.assert.strictEqual(res.statusCode, 200)
1925
+ t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'world' })
1926
+ testDone()
1927
+ })
1928
+ })
1929
+
1930
+ test('Register hooks inside a plugin after an encapsulated plugin', (t, testDone) => {
1931
+ t.plan(7)
1932
+ const fastify = Fastify()
1933
+
1934
+ fastify.register(function (instance, opts, done) {
1935
+ instance.get('/', function (request, reply) {
1936
+ reply.send({ hello: 'world' })
1937
+ })
1938
+
1939
+ done()
1940
+ })
1941
+
1942
+ fastify.register(fp(function (instance, opts, done) {
1943
+ instance.addHook('onRequest', function (req, reply, done) {
1944
+ t.assert.ok('called')
1945
+ done()
1946
+ })
1947
+
1948
+ instance.addHook('preHandler', function (request, reply, done) {
1949
+ t.assert.ok('called')
1950
+ done()
1951
+ })
1952
+
1953
+ instance.addHook('onSend', function (request, reply, payload, done) {
1954
+ t.assert.ok('called')
1955
+ done()
1956
+ })
1957
+
1958
+ instance.addHook('onResponse', function (request, reply, done) {
1959
+ t.assert.ok('called')
1960
+ done()
1961
+ })
1962
+
1963
+ done()
1964
+ }))
1965
+
1966
+ fastify.inject('/', (err, res) => {
1967
+ t.assert.ifError(err)
1968
+ t.assert.strictEqual(res.statusCode, 200)
1969
+ t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'world' })
1970
+ testDone()
1971
+ })
1972
+ })
1973
+
1974
+ test('onRequest hooks should run in the order in which they are defined', (t, testDone) => {
1975
+ t.plan(9)
1976
+ const fastify = Fastify()
1977
+
1978
+ fastify.register(function (instance, opts, done) {
1979
+ instance.addHook('onRequest', function (req, reply, done) {
1980
+ t.assert.strictEqual(req.previous, undefined)
1981
+ req.previous = 1
1982
+ done()
1983
+ })
1984
+
1985
+ instance.get('/', function (request, reply) {
1986
+ t.assert.strictEqual(request.previous, 5)
1987
+ reply.send({ hello: 'world' })
1988
+ })
1989
+
1990
+ instance.register(fp(function (i, opts, done) {
1991
+ i.addHook('onRequest', function (req, reply, done) {
1992
+ t.assert.strictEqual(req.previous, 1)
1993
+ req.previous = 2
1994
+ done()
1995
+ })
1996
+ done()
1997
+ }))
1998
+
1999
+ done()
2000
+ })
2001
+
2002
+ fastify.register(fp(function (instance, opts, done) {
2003
+ instance.addHook('onRequest', function (req, reply, done) {
2004
+ t.assert.strictEqual(req.previous, 2)
2005
+ req.previous = 3
2006
+ done()
2007
+ })
2008
+
2009
+ instance.register(fp(function (i, opts, done) {
2010
+ i.addHook('onRequest', function (req, reply, done) {
2011
+ t.assert.strictEqual(req.previous, 3)
2012
+ req.previous = 4
2013
+ done()
2014
+ })
2015
+ done()
2016
+ }))
2017
+
2018
+ instance.addHook('onRequest', function (req, reply, done) {
2019
+ t.assert.strictEqual(req.previous, 4)
2020
+ req.previous = 5
2021
+ done()
2022
+ })
2023
+
2024
+ done()
2025
+ }))
2026
+
2027
+ fastify.inject('/', (err, res) => {
2028
+ t.assert.ifError(err)
2029
+ t.assert.strictEqual(res.statusCode, 200)
2030
+ t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'world' })
2031
+ testDone()
2032
+ })
2033
+ })
2034
+
2035
+ test('preHandler hooks should run in the order in which they are defined', (t, testDone) => {
2036
+ t.plan(9)
2037
+ const fastify = Fastify()
2038
+
2039
+ fastify.register(function (instance, opts, done) {
2040
+ instance.addHook('preHandler', function (request, reply, done) {
2041
+ t.assert.strictEqual(request.previous, undefined)
2042
+ request.previous = 1
2043
+ done()
2044
+ })
2045
+
2046
+ instance.get('/', function (request, reply) {
2047
+ t.assert.strictEqual(request.previous, 5)
2048
+ reply.send({ hello: 'world' })
2049
+ })
2050
+
2051
+ instance.register(fp(function (i, opts, done) {
2052
+ i.addHook('preHandler', function (request, reply, done) {
2053
+ t.assert.strictEqual(request.previous, 1)
2054
+ request.previous = 2
2055
+ done()
2056
+ })
2057
+ done()
2058
+ }))
2059
+
2060
+ done()
2061
+ })
2062
+
2063
+ fastify.register(fp(function (instance, opts, done) {
2064
+ instance.addHook('preHandler', function (request, reply, done) {
2065
+ t.assert.strictEqual(request.previous, 2)
2066
+ request.previous = 3
2067
+ done()
2068
+ })
2069
+
2070
+ instance.register(fp(function (i, opts, done) {
2071
+ i.addHook('preHandler', function (request, reply, done) {
2072
+ t.assert.strictEqual(request.previous, 3)
2073
+ request.previous = 4
2074
+ done()
2075
+ })
2076
+ done()
2077
+ }))
2078
+
2079
+ instance.addHook('preHandler', function (request, reply, done) {
2080
+ t.assert.strictEqual(request.previous, 4)
2081
+ request.previous = 5
2082
+ done()
2083
+ })
2084
+
2085
+ done()
2086
+ }))
2087
+
2088
+ fastify.inject('/', (err, res) => {
2089
+ t.assert.ifError(err)
2090
+ t.assert.strictEqual(res.statusCode, 200)
2091
+ t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'world' })
2092
+ testDone()
2093
+ })
2094
+ })
2095
+
2096
+ test('onSend hooks should run in the order in which they are defined', (t, testDone) => {
2097
+ t.plan(8)
2098
+ const fastify = Fastify()
2099
+
2100
+ fastify.register(function (instance, opts, done) {
2101
+ instance.addHook('onSend', function (request, reply, payload, done) {
2102
+ t.assert.strictEqual(request.previous, undefined)
2103
+ request.previous = 1
2104
+ done()
2105
+ })
2106
+
2107
+ instance.get('/', function (request, reply) {
2108
+ reply.send({})
2109
+ })
2110
+
2111
+ instance.register(fp(function (i, opts, done) {
2112
+ i.addHook('onSend', function (request, reply, payload, done) {
2113
+ t.assert.strictEqual(request.previous, 1)
2114
+ request.previous = 2
2115
+ done()
2116
+ })
2117
+ done()
2118
+ }))
2119
+
2120
+ done()
2121
+ })
2122
+
2123
+ fastify.register(fp(function (instance, opts, done) {
2124
+ instance.addHook('onSend', function (request, reply, payload, done) {
2125
+ t.assert.strictEqual(request.previous, 2)
2126
+ request.previous = 3
2127
+ done()
2128
+ })
2129
+
2130
+ instance.register(fp(function (i, opts, done) {
2131
+ i.addHook('onSend', function (request, reply, payload, done) {
2132
+ t.assert.strictEqual(request.previous, 3)
2133
+ request.previous = 4
2134
+ done()
2135
+ })
2136
+ done()
2137
+ }))
2138
+
2139
+ instance.addHook('onSend', function (request, reply, payload, done) {
2140
+ t.assert.strictEqual(request.previous, 4)
2141
+ done(null, '5')
2142
+ })
2143
+
2144
+ done()
2145
+ }))
2146
+
2147
+ fastify.inject('/', (err, res) => {
2148
+ t.assert.ifError(err)
2149
+ t.assert.strictEqual(res.statusCode, 200)
2150
+ t.assert.deepStrictEqual(JSON.parse(res.payload), 5)
2151
+ testDone()
2152
+ })
2153
+ })
2154
+
2155
+ test('onResponse hooks should run in the order in which they are defined', (t, testDone) => {
2156
+ t.plan(8)
2157
+ const fastify = Fastify()
2158
+
2159
+ fastify.register(function (instance, opts, done) {
2160
+ instance.addHook('onResponse', function (request, reply, done) {
2161
+ t.assert.strictEqual(reply.previous, undefined)
2162
+ reply.previous = 1
2163
+ done()
2164
+ })
2165
+
2166
+ instance.get('/', function (request, reply) {
2167
+ reply.send({ hello: 'world' })
2168
+ })
2169
+
2170
+ instance.register(fp(function (i, opts, done) {
2171
+ i.addHook('onResponse', function (request, reply, done) {
2172
+ t.assert.strictEqual(reply.previous, 1)
2173
+ reply.previous = 2
2174
+ done()
2175
+ })
2176
+ done()
2177
+ }))
2178
+
2179
+ done()
2180
+ })
2181
+
2182
+ fastify.register(fp(function (instance, opts, done) {
2183
+ instance.addHook('onResponse', function (request, reply, done) {
2184
+ t.assert.strictEqual(reply.previous, 2)
2185
+ reply.previous = 3
2186
+ done()
2187
+ })
2188
+
2189
+ instance.register(fp(function (i, opts, done) {
2190
+ i.addHook('onResponse', function (request, reply, done) {
2191
+ t.assert.strictEqual(reply.previous, 3)
2192
+ reply.previous = 4
2193
+ done()
2194
+ })
2195
+ done()
2196
+ }))
2197
+
2198
+ instance.addHook('onResponse', function (request, reply, done) {
2199
+ t.assert.strictEqual(reply.previous, 4)
2200
+ done()
2201
+ })
2202
+
2203
+ done()
2204
+ }))
2205
+
2206
+ fastify.inject('/', (err, res) => {
2207
+ t.assert.ifError(err)
2208
+ t.assert.strictEqual(res.statusCode, 200)
2209
+ t.assert.deepStrictEqual(JSON.parse(res.payload), { hello: 'world' })
2210
+ testDone()
2211
+ })
2212
+ })
2213
+
2214
+ test('onRequest, preHandler, and onResponse hooks that resolve to a value do not cause an error', (t, testDone) => {
2215
+ t.plan(3)
2216
+ const fastify = Fastify()
2217
+
2218
+ fastify
2219
+ .addHook('onRequest', () => Promise.resolve(1))
2220
+ .addHook('onRequest', () => Promise.resolve(true))
2221
+ .addHook('preValidation', () => Promise.resolve(null))
2222
+ .addHook('preValidation', () => Promise.resolve('a'))
2223
+ .addHook('preHandler', () => Promise.resolve(null))
2224
+ .addHook('preHandler', () => Promise.resolve('a'))
2225
+ .addHook('onResponse', () => Promise.resolve({}))
2226
+ .addHook('onResponse', () => Promise.resolve([]))
2227
+
2228
+ fastify.get('/', (request, reply) => {
2229
+ reply.send('hello')
2230
+ })
2231
+
2232
+ fastify.inject('/', (err, res) => {
2233
+ t.assert.ifError(err)
2234
+ t.assert.strictEqual(res.statusCode, 200)
2235
+ t.assert.strictEqual(res.payload, 'hello')
2236
+ testDone()
2237
+ })
2238
+ })
2239
+
2240
+ test('If a response header has been set inside an hook it should not be overwritten by the final response handler', (t, testDone) => {
2241
+ t.plan(5)
2242
+ const fastify = Fastify()
2243
+
2244
+ fastify.addHook('onRequest', (req, reply, done) => {
2245
+ reply.header('X-Custom-Header', 'hello')
2246
+ done()
2247
+ })
2248
+
2249
+ fastify.get('/', (request, reply) => {
2250
+ reply.send('hello')
2251
+ })
2252
+
2253
+ fastify.inject('/', (err, res) => {
2254
+ t.assert.ifError(err)
2255
+ t.assert.strictEqual(res.headers['x-custom-header'], 'hello')
2256
+ t.assert.strictEqual(res.headers['content-type'], 'text/plain; charset=utf-8')
2257
+ t.assert.strictEqual(res.statusCode, 200)
2258
+ t.assert.strictEqual(res.payload, 'hello')
2259
+ testDone()
2260
+ })
2261
+ })
2262
+
2263
+ test('If the content type has been set inside an hook it should not be changed', (t, testDone) => {
2264
+ t.plan(5)
2265
+ const fastify = Fastify()
2266
+
2267
+ fastify.addHook('onRequest', (req, reply, done) => {
2268
+ reply.header('content-type', 'text/html')
2269
+ done()
2270
+ })
2271
+
2272
+ fastify.get('/', (request, reply) => {
2273
+ t.assert.ok(reply[symbols.kReplyHeaders]['content-type'])
2274
+ reply.send('hello')
2275
+ })
2276
+
2277
+ fastify.inject('/', (err, res) => {
2278
+ t.assert.ifError(err)
2279
+ t.assert.strictEqual(res.headers['content-type'], 'text/html')
2280
+ t.assert.strictEqual(res.statusCode, 200)
2281
+ t.assert.strictEqual(res.payload, 'hello')
2282
+ testDone()
2283
+ })
2284
+ })
2285
+
2286
+ test('request in onRequest, preParsing, preValidation and onResponse', (t, testDone) => {
2287
+ t.plan(18)
2288
+ const fastify = Fastify()
2289
+
2290
+ fastify.addHook('onRequest', function (request, reply, done) {
2291
+ t.assert.deepStrictEqual(request.body, undefined)
2292
+ t.assert.deepStrictEqual(request.query.key, 'value')
2293
+ t.assert.deepStrictEqual(request.params.greeting, 'hello')
2294
+ t.assert.deepStrictEqual(request.headers, {
2295
+ 'content-length': '17',
2296
+ 'content-type': 'application/json',
2297
+ host: 'localhost:80',
2298
+ 'user-agent': 'lightMyRequest',
2299
+ 'x-custom': 'hello'
2300
+ })
2301
+ done()
2302
+ })
2303
+
2304
+ fastify.addHook('preParsing', function (request, reply, payload, done) {
2305
+ t.assert.deepStrictEqual(request.body, undefined)
2306
+ t.assert.deepStrictEqual(request.query.key, 'value')
2307
+ t.assert.deepStrictEqual(request.params.greeting, 'hello')
2308
+ t.assert.deepStrictEqual(request.headers, {
2309
+ 'content-length': '17',
2310
+ 'content-type': 'application/json',
2311
+ host: 'localhost:80',
2312
+ 'user-agent': 'lightMyRequest',
2313
+ 'x-custom': 'hello'
2314
+ })
2315
+ done()
2316
+ })
2317
+
2318
+ fastify.addHook('preValidation', function (request, reply, done) {
2319
+ t.assert.deepStrictEqual(request.body, { hello: 'world' })
2320
+ t.assert.deepStrictEqual(request.query.key, 'value')
2321
+ t.assert.deepStrictEqual(request.params.greeting, 'hello')
2322
+ t.assert.deepStrictEqual(request.headers, {
2323
+ 'content-length': '17',
2324
+ 'content-type': 'application/json',
2325
+ host: 'localhost:80',
2326
+ 'user-agent': 'lightMyRequest',
2327
+ 'x-custom': 'hello'
2328
+ })
2329
+ done()
2330
+ })
2331
+
2332
+ fastify.addHook('onResponse', function (request, reply, done) {
2333
+ t.assert.deepStrictEqual(request.body, { hello: 'world' })
2334
+ t.assert.deepStrictEqual(request.query.key, 'value')
2335
+ t.assert.deepStrictEqual(request.params.greeting, 'hello')
2336
+ t.assert.deepStrictEqual(request.headers, {
2337
+ 'content-length': '17',
2338
+ 'content-type': 'application/json',
2339
+ host: 'localhost:80',
2340
+ 'user-agent': 'lightMyRequest',
2341
+ 'x-custom': 'hello'
2342
+ })
2343
+ done()
2344
+ })
2345
+
2346
+ fastify.post('/:greeting', function (req, reply) {
2347
+ reply.send('ok')
2348
+ })
2349
+
2350
+ fastify.inject({
2351
+ method: 'POST',
2352
+ url: '/hello?key=value',
2353
+ headers: { 'x-custom': 'hello' },
2354
+ payload: { hello: 'world' }
2355
+ }, (err, res) => {
2356
+ t.assert.ifError(err)
2357
+ t.assert.strictEqual(res.statusCode, 200)
2358
+ testDone()
2359
+ })
2360
+ })
2361
+
2362
+ test('preValidation hook should support encapsulation / 1', (t, testDone) => {
2363
+ t.plan(5)
2364
+ const fastify = Fastify()
2365
+
2366
+ fastify.register((instance, opts, done) => {
2367
+ instance.addHook('preValidation', (req, reply, done) => {
2368
+ t.assert.strictEqual(req.raw.url, '/plugin')
2369
+ done()
2370
+ })
2371
+
2372
+ instance.get('/plugin', (request, reply) => {
2373
+ reply.send()
2374
+ })
2375
+
2376
+ done()
2377
+ })
2378
+
2379
+ fastify.get('/root', (request, reply) => {
2380
+ reply.send()
2381
+ })
2382
+
2383
+ fastify.inject('/root', (err, res) => {
2384
+ t.assert.ifError(err)
2385
+ t.assert.strictEqual(res.statusCode, 200)
2386
+ fastify.inject('/plugin', (err, res) => {
2387
+ t.assert.ifError(err)
2388
+ t.assert.strictEqual(res.statusCode, 200)
2389
+ testDone()
2390
+ })
2391
+ })
2392
+ })
2393
+
2394
+ test('preValidation hook should support encapsulation / 2', (t, testDone) => {
2395
+ t.plan(3)
2396
+ const fastify = Fastify()
2397
+ let pluginInstance
2398
+
2399
+ fastify.addHook('preValidation', () => { })
2400
+
2401
+ fastify.register((instance, opts, done) => {
2402
+ instance.addHook('preValidation', () => { })
2403
+ pluginInstance = instance
2404
+ done()
2405
+ })
2406
+
2407
+ fastify.ready(err => {
2408
+ t.assert.ifError(err)
2409
+ t.assert.strictEqual(fastify[symbols.kHooks].preValidation.length, 1)
2410
+ t.assert.strictEqual(pluginInstance[symbols.kHooks].preValidation.length, 2)
2411
+ testDone()
2412
+ })
2413
+ })
2414
+
2415
+ test('preValidation hook should support encapsulation / 3', async t => {
2416
+ t.plan(19)
2417
+ const fastify = Fastify()
2418
+ t.after(() => { fastify.close() })
2419
+ fastify.decorate('hello', 'world')
2420
+
2421
+ fastify.addHook('preValidation', function (req, reply, done) {
2422
+ t.assert.ok(this.hello)
2423
+ t.assert.ok(this.hello2)
2424
+ req.first = true
2425
+ done()
2426
+ })
2427
+
2428
+ fastify.decorate('hello2', 'world')
2429
+
2430
+ fastify.get('/first', (req, reply) => {
2431
+ t.assert.ok(req.first)
2432
+ t.assert.ok(!req.second)
2433
+ reply.send({ hello: 'world' })
2434
+ })
2435
+
2436
+ fastify.register((instance, opts, done) => {
2437
+ instance.decorate('hello3', 'world')
2438
+ instance.addHook('preValidation', function (req, reply, done) {
2439
+ t.assert.ok(this.hello)
2440
+ t.assert.ok(this.hello2)
2441
+ t.assert.ok(this.hello3)
2442
+ req.second = true
2443
+ done()
2444
+ })
2445
+
2446
+ instance.get('/second', (req, reply) => {
2447
+ t.assert.ok(req.first)
2448
+ t.assert.ok(req.second)
2449
+ reply.send({ hello: 'world' })
2450
+ })
2451
+
2452
+ done()
2453
+ })
2454
+
2455
+ const fastifyServer = await fastify.listen({ port: 0 })
2456
+
2457
+ const result1 = await fetch(fastifyServer + '/first')
2458
+ t.assert.ok(result1.ok)
2459
+ t.assert.strictEqual(result1.status, 200)
2460
+ const body1 = await result1.text()
2461
+ t.assert.strictEqual(result1.headers.get('content-length'), '' + body1.length)
2462
+ t.assert.deepStrictEqual(JSON.parse(body1), { hello: 'world' })
2463
+
2464
+ const result2 = await fetch(fastifyServer + '/second')
2465
+ t.assert.ok(result2.ok)
2466
+ t.assert.strictEqual(result2.status, 200)
2467
+ const body2 = await result2.text()
2468
+ t.assert.strictEqual(result2.headers.get('content-length'), '' + body2.length)
2469
+ t.assert.deepStrictEqual(JSON.parse(body2), { hello: 'world' })
2470
+ })
2471
+
2472
+ test('onError hook', (t, testDone) => {
2473
+ t.plan(3)
2474
+
2475
+ const fastify = Fastify()
2476
+
2477
+ const err = new Error('kaboom')
2478
+
2479
+ fastify.addHook('onError', (request, reply, error, done) => {
2480
+ t.assert.deepStrictEqual(error, err)
2481
+ done()
2482
+ })
2483
+
2484
+ fastify.get('/', (req, reply) => {
2485
+ reply.send(err)
2486
+ })
2487
+
2488
+ fastify.inject({
2489
+ method: 'GET',
2490
+ url: '/'
2491
+ }, (err, res) => {
2492
+ t.assert.ifError(err)
2493
+ t.assert.deepStrictEqual(JSON.parse(res.payload), {
2494
+ error: 'Internal Server Error',
2495
+ message: 'kaboom',
2496
+ statusCode: 500
2497
+ })
2498
+ testDone()
2499
+ })
2500
+ })
2501
+
2502
+ test('reply.send should throw if called inside the onError hook', (t, testDone) => {
2503
+ t.plan(3)
2504
+
2505
+ const fastify = Fastify()
2506
+
2507
+ const err = new Error('kaboom')
2508
+
2509
+ fastify.addHook('onError', (request, reply, error, done) => {
2510
+ try {
2511
+ reply.send()
2512
+ t.assert.fail('Should throw')
2513
+ } catch (err) {
2514
+ t.assert.strictEqual(err.code, 'FST_ERR_SEND_INSIDE_ONERR')
2515
+ }
2516
+ done()
2517
+ })
2518
+
2519
+ fastify.get('/', (req, reply) => {
2520
+ reply.send(err)
2521
+ })
2522
+
2523
+ fastify.inject({
2524
+ method: 'GET',
2525
+ url: '/'
2526
+ }, (err, res) => {
2527
+ t.assert.ifError(err)
2528
+ t.assert.deepStrictEqual(JSON.parse(res.payload), {
2529
+ error: 'Internal Server Error',
2530
+ message: 'kaboom',
2531
+ statusCode: 500
2532
+ })
2533
+ testDone()
2534
+ })
2535
+ })
2536
+
2537
+ test('onError hook with setErrorHandler', (t, testDone) => {
2538
+ t.plan(3)
2539
+
2540
+ const fastify = Fastify()
2541
+
2542
+ const external = new Error('ouch')
2543
+ const internal = new Error('kaboom')
2544
+
2545
+ fastify.setErrorHandler((_, req, reply) => {
2546
+ reply.send(external)
2547
+ })
2548
+
2549
+ fastify.addHook('onError', (request, reply, error, done) => {
2550
+ t.assert.deepStrictEqual(error, internal)
2551
+ done()
2552
+ })
2553
+
2554
+ fastify.get('/', (req, reply) => {
2555
+ reply.send(internal)
2556
+ })
2557
+
2558
+ fastify.inject({
2559
+ method: 'GET',
2560
+ url: '/'
2561
+ }, (err, res) => {
2562
+ t.assert.ifError(err)
2563
+ t.assert.deepStrictEqual(JSON.parse(res.payload), {
2564
+ error: 'Internal Server Error',
2565
+ message: 'ouch',
2566
+ statusCode: 500
2567
+ })
2568
+ testDone()
2569
+ })
2570
+ })
2571
+
2572
+ test('preParsing hook should run before parsing and be able to modify the payload', async t => {
2573
+ t.plan(4)
2574
+ const fastify = Fastify()
2575
+ t.after(() => { fastify.close() })
2576
+
2577
+ fastify.addHook('preParsing', function (req, reply, payload, done) {
2578
+ const modified = new stream.Readable()
2579
+ modified.receivedEncodedLength = parseInt(req.headers['content-length'], 10)
2580
+ modified.push(JSON.stringify({ hello: 'another world' }))
2581
+ modified.push(null)
2582
+ done(null, modified)
2583
+ })
2584
+
2585
+ fastify.route({
2586
+ method: 'POST',
2587
+ url: '/first',
2588
+ handler: function (req, reply) {
2589
+ reply.send(req.body)
2590
+ }
2591
+ })
2592
+
2593
+ const fastifyServer = await fastify.listen({ port: 0 })
2594
+
2595
+ const result = await fetch(fastifyServer + '/first', {
2596
+ method: 'POST',
2597
+ body: JSON.stringify({ hello: 'world' }),
2598
+ headers: { 'Content-Type': 'application/json' }
2599
+ })
2600
+ t.assert.ok(result.ok)
2601
+ t.assert.strictEqual(result.status, 200)
2602
+ const body = await result.text()
2603
+ t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
2604
+ t.assert.deepStrictEqual(JSON.parse(body), { hello: 'another world' })
2605
+ })
2606
+
2607
+ test('preParsing hooks should run in the order in which they are defined', async t => {
2608
+ t.plan(4)
2609
+ const fastify = Fastify()
2610
+ t.after(() => { fastify.close() })
2611
+
2612
+ fastify.addHook('preParsing', function (req, reply, payload, done) {
2613
+ const modified = new stream.Readable()
2614
+ modified.receivedEncodedLength = parseInt(req.headers['content-length'], 10)
2615
+ modified.push('{"hello":')
2616
+ done(null, modified)
2617
+ })
2618
+
2619
+ fastify.addHook('preParsing', function (req, reply, payload, done) {
2620
+ payload.push('"another world"}')
2621
+ payload.push(null)
2622
+ done(null, payload)
2623
+ })
2624
+
2625
+ fastify.route({
2626
+ method: 'POST',
2627
+ url: '/first',
2628
+ handler: function (req, reply) {
2629
+ reply.send(req.body)
2630
+ }
2631
+ })
2632
+
2633
+ const fastifyServer = await fastify.listen({ port: 0 })
2634
+
2635
+ const result = await fetch(fastifyServer + '/first', {
2636
+ method: 'POST',
2637
+ body: JSON.stringify({ hello: 'world' }),
2638
+ headers: { 'Content-Type': 'application/json' }
2639
+ })
2640
+ t.assert.ok(result.ok)
2641
+ t.assert.strictEqual(result.status, 200)
2642
+ const body = await result.text()
2643
+ t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
2644
+ t.assert.deepStrictEqual(JSON.parse(body), { hello: 'another world' })
2645
+ })
2646
+
2647
+ test('preParsing hooks should support encapsulation', async t => {
2648
+ t.plan(8)
2649
+ const fastify = Fastify()
2650
+ t.after(() => { fastify.close() })
2651
+
2652
+ fastify.addHook('preParsing', function (req, reply, payload, done) {
2653
+ const modified = new stream.Readable()
2654
+ modified.receivedEncodedLength = parseInt(req.headers['content-length'], 10)
2655
+ modified.push('{"hello":"another world"}')
2656
+ modified.push(null)
2657
+ done(null, modified)
2658
+ })
2659
+
2660
+ fastify.post('/first', (req, reply) => {
2661
+ reply.send(req.body)
2662
+ })
2663
+
2664
+ fastify.register((instance, opts, done) => {
2665
+ instance.addHook('preParsing', function (req, reply, payload, done) {
2666
+ const modified = new stream.Readable()
2667
+ modified.receivedEncodedLength = payload.receivedEncodedLength || parseInt(req.headers['content-length'], 10)
2668
+ modified.push('{"hello":"encapsulated world"}')
2669
+ modified.push(null)
2670
+ done(null, modified)
2671
+ })
2672
+
2673
+ instance.post('/second', (req, reply) => {
2674
+ reply.send(req.body)
2675
+ })
2676
+
2677
+ done()
2678
+ })
2679
+
2680
+ const fastifyServer = await fastify.listen({ port: 0 })
2681
+
2682
+ const result1 = await fetch(fastifyServer + '/first', {
2683
+ method: 'POST',
2684
+ body: JSON.stringify({ hello: 'world' }),
2685
+ headers: { 'Content-Type': 'application/json' }
2686
+ })
2687
+ t.assert.ok(result1.ok)
2688
+ t.assert.strictEqual(result1.status, 200)
2689
+ const body1 = await result1.text()
2690
+ t.assert.strictEqual(result1.headers.get('content-length'), '' + body1.length)
2691
+ t.assert.deepStrictEqual(JSON.parse(body1), { hello: 'another world' })
2692
+
2693
+ const result2 = await fetch(fastifyServer + '/second', {
2694
+ method: 'POST',
2695
+ body: JSON.stringify({ hello: 'world' }),
2696
+ headers: { 'Content-Type': 'application/json' }
2697
+ })
2698
+ t.assert.ok(result2.ok)
2699
+ t.assert.strictEqual(result2.status, 200)
2700
+ const body2 = await result2.text()
2701
+ t.assert.strictEqual(result2.headers.get('content-length'), '' + body2.length)
2702
+ t.assert.deepStrictEqual(JSON.parse(body2), { hello: 'encapsulated world' })
2703
+ })
2704
+
2705
+ test('preParsing hook should support encapsulation / 1', (t, testDone) => {
2706
+ t.plan(5)
2707
+ const fastify = Fastify()
2708
+
2709
+ fastify.register((instance, opts, done) => {
2710
+ instance.addHook('preParsing', (req, reply, payload, done) => {
2711
+ t.assert.strictEqual(req.raw.url, '/plugin')
2712
+ done()
2713
+ })
2714
+
2715
+ instance.get('/plugin', (request, reply) => {
2716
+ reply.send()
2717
+ })
2718
+
2719
+ done()
2720
+ })
2721
+
2722
+ fastify.get('/root', (request, reply) => {
2723
+ reply.send()
2724
+ })
2725
+
2726
+ fastify.inject('/root', (err, res) => {
2727
+ t.assert.ifError(err)
2728
+ t.assert.strictEqual(res.statusCode, 200)
2729
+ fastify.inject('/plugin', (err, res) => {
2730
+ t.assert.ifError(err)
2731
+ t.assert.strictEqual(res.statusCode, 200)
2732
+ testDone()
2733
+ })
2734
+ })
2735
+ })
2736
+
2737
+ test('preParsing hook should support encapsulation / 2', (t, testDone) => {
2738
+ t.plan(3)
2739
+ const fastify = Fastify()
2740
+ let pluginInstance
2741
+
2742
+ fastify.addHook('preParsing', function a () { })
2743
+
2744
+ fastify.register((instance, opts, done) => {
2745
+ instance.addHook('preParsing', function b () { })
2746
+ pluginInstance = instance
2747
+ done()
2748
+ })
2749
+
2750
+ fastify.ready(err => {
2751
+ t.assert.ifError(err)
2752
+ t.assert.strictEqual(fastify[symbols.kHooks].preParsing.length, 1)
2753
+ t.assert.strictEqual(pluginInstance[symbols.kHooks].preParsing.length, 2)
2754
+ testDone()
2755
+ })
2756
+ })
2757
+
2758
+ test('preParsing hook should support encapsulation / 3', async t => {
2759
+ t.plan(19)
2760
+ const fastify = Fastify()
2761
+ t.after(() => { fastify.close() })
2762
+ fastify.decorate('hello', 'world')
2763
+
2764
+ fastify.addHook('preParsing', function (req, reply, payload, done) {
2765
+ t.assert.ok(this.hello)
2766
+ t.assert.ok(this.hello2)
2767
+ req.first = true
2768
+ done()
2769
+ })
2770
+
2771
+ fastify.decorate('hello2', 'world')
2772
+
2773
+ fastify.get('/first', (req, reply) => {
2774
+ t.assert.ok(req.first)
2775
+ t.assert.ok(!req.second)
2776
+ reply.send({ hello: 'world' })
2777
+ })
2778
+
2779
+ fastify.register((instance, opts, done) => {
2780
+ instance.decorate('hello3', 'world')
2781
+ instance.addHook('preParsing', function (req, reply, payload, done) {
2782
+ t.assert.ok(this.hello)
2783
+ t.assert.ok(this.hello2)
2784
+ t.assert.ok(this.hello3)
2785
+ req.second = true
2786
+ done()
2787
+ })
2788
+
2789
+ instance.get('/second', (req, reply) => {
2790
+ t.assert.ok(req.first)
2791
+ t.assert.ok(req.second)
2792
+ reply.send({ hello: 'world' })
2793
+ })
2794
+
2795
+ done()
2796
+ })
2797
+
2798
+ const fastifyServer = await fastify.listen({ port: 0 })
2799
+
2800
+ const result1 = await fetch(fastifyServer + '/first')
2801
+ t.assert.ok(result1.ok)
2802
+ t.assert.strictEqual(result1.status, 200)
2803
+ const body1 = await result1.text()
2804
+ t.assert.strictEqual(result1.headers.get('content-length'), '' + body1.length)
2805
+ t.assert.deepStrictEqual(JSON.parse(body1), { hello: 'world' })
2806
+
2807
+ const result2 = await fetch(fastifyServer + '/second')
2808
+ t.assert.ok(result2.ok)
2809
+ t.assert.strictEqual(result2.status, 200)
2810
+ const body2 = await result2.text()
2811
+ t.assert.strictEqual(result2.headers.get('content-length'), '' + body2.length)
2812
+ t.assert.deepStrictEqual(JSON.parse(body2), { hello: 'world' })
2813
+ })
2814
+
2815
+ test('preSerialization hook should run before serialization and be able to modify the payload', async t => {
2816
+ t.plan(4)
2817
+ const fastify = Fastify()
2818
+ t.after(() => { fastify.close() })
2819
+
2820
+ fastify.addHook('preSerialization', function (req, reply, payload, done) {
2821
+ payload.hello += '1'
2822
+ payload.world = 'ok'
2823
+
2824
+ done(null, payload)
2825
+ })
2826
+
2827
+ fastify.route({
2828
+ method: 'GET',
2829
+ url: '/first',
2830
+ handler: function (req, reply) {
2831
+ reply.send({ hello: 'world' })
2832
+ },
2833
+ schema: {
2834
+ response: {
2835
+ 200: {
2836
+ type: 'object',
2837
+ properties: {
2838
+ hello: {
2839
+ type: 'string'
2840
+ },
2841
+ world: {
2842
+ type: 'string'
2843
+ }
2844
+ },
2845
+ required: ['world'],
2846
+ additionalProperties: false
2847
+ }
2848
+ }
2849
+ }
2850
+ })
2851
+
2852
+ const fastifyServer = await fastify.listen({ port: 0 })
2853
+
2854
+ const result = await fetch(fastifyServer + '/first')
2855
+ t.assert.ok(result.ok)
2856
+ t.assert.strictEqual(result.status, 200)
2857
+ const body = await result.text()
2858
+ t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
2859
+ t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world1', world: 'ok' })
2860
+ })
2861
+
2862
+ test('preSerialization hook should be able to throw errors which are validated against schema response', async t => {
2863
+ t.plan(5)
2864
+ const fastify = Fastify()
2865
+ t.after(() => { fastify.close() })
2866
+
2867
+ fastify.addHook('preSerialization', function (req, reply, payload, done) {
2868
+ done(new Error('preSerialization aborted'))
2869
+ })
2870
+
2871
+ fastify.setErrorHandler((err, request, reply) => {
2872
+ t.assert.strictEqual(err.message, 'preSerialization aborted')
2873
+ err.world = 'error'
2874
+ reply.send(err)
2875
+ })
2876
+
2877
+ fastify.route({
2878
+ method: 'GET',
2879
+ url: '/first',
2880
+ handler: function (req, reply) {
2881
+ reply.send({ world: 'hello' })
2882
+ },
2883
+ schema: {
2884
+ response: {
2885
+ 500: {
2886
+ type: 'object',
2887
+ properties: {
2888
+ world: {
2889
+ type: 'string'
2890
+ }
2891
+ },
2892
+ required: ['world'],
2893
+ additionalProperties: false
2894
+ }
2895
+ }
2896
+ }
2897
+ })
2898
+
2899
+ const fastifyServer = await fastify.listen({ port: 0 })
2900
+
2901
+ const result = await fetch(fastifyServer + '/first')
2902
+ t.assert.ok(!result.ok)
2903
+ t.assert.strictEqual(result.status, 500)
2904
+ const body = await result.text()
2905
+ t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
2906
+ t.assert.deepStrictEqual(JSON.parse(body), { world: 'error' })
2907
+ })
2908
+
2909
+ test('preSerialization hook which returned error should still run onError hooks', async t => {
2910
+ t.plan(3)
2911
+ const fastify = Fastify()
2912
+ t.after(() => { fastify.close() })
2913
+
2914
+ fastify.addHook('preSerialization', function (req, reply, payload, done) {
2915
+ done(new Error('preSerialization aborted'))
2916
+ })
2917
+
2918
+ fastify.addHook('onError', function (req, reply, payload, done) {
2919
+ t.assert.ok('should pass')
2920
+ done()
2921
+ })
2922
+
2923
+ fastify.get('/first', (req, reply) => {
2924
+ reply.send({ hello: 'world' })
2925
+ })
2926
+
2927
+ const fastifyServer = await fastify.listen({ port: 0 })
2928
+
2929
+ const result = await fetch(fastifyServer + '/first')
2930
+ t.assert.ok(!result.ok)
2931
+ t.assert.strictEqual(result.status, 500)
2932
+ })
2933
+
2934
+ test('preSerialization hooks should run in the order in which they are defined', async t => {
2935
+ t.plan(4)
2936
+ const fastify = Fastify()
2937
+ t.after(() => { fastify.close() })
2938
+
2939
+ fastify.addHook('preSerialization', function (req, reply, payload, done) {
2940
+ payload.hello += '2'
2941
+
2942
+ done(null, payload)
2943
+ })
2944
+
2945
+ fastify.addHook('preSerialization', function (req, reply, payload, done) {
2946
+ payload.hello += '1'
2947
+
2948
+ done(null, payload)
2949
+ })
2950
+
2951
+ fastify.get('/first', (req, reply) => {
2952
+ reply.send({ hello: 'world' })
2953
+ })
2954
+
2955
+ const fastifyServer = await fastify.listen({ port: 0 })
2956
+
2957
+ const result = await fetch(fastifyServer + '/first')
2958
+ t.assert.ok(result.ok)
2959
+ t.assert.strictEqual(result.status, 200)
2960
+ const body = await result.text()
2961
+ t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
2962
+ t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world21' })
2963
+ })
2964
+
2965
+ test('preSerialization hooks should support encapsulation', async t => {
2966
+ t.plan(8)
2967
+ const fastify = Fastify()
2968
+ t.after(() => { fastify.close() })
2969
+
2970
+ fastify.addHook('preSerialization', function (req, reply, payload, done) {
2971
+ payload.hello += '1'
2972
+
2973
+ done(null, payload)
2974
+ })
2975
+
2976
+ fastify.get('/first', (req, reply) => {
2977
+ reply.send({ hello: 'world' })
2978
+ })
2979
+
2980
+ fastify.register((instance, opts, done) => {
2981
+ instance.addHook('preSerialization', function (req, reply, payload, done) {
2982
+ payload.hello += '2'
2983
+
2984
+ done(null, payload)
2985
+ })
2986
+
2987
+ instance.get('/second', (req, reply) => {
2988
+ reply.send({ hello: 'world' })
2989
+ })
2990
+
2991
+ done()
2992
+ })
2993
+
2994
+ const fastifyServer = await fastify.listen({ port: 0 })
2995
+
2996
+ const result1 = await fetch(fastifyServer + '/first')
2997
+ t.assert.ok(result1.ok)
2998
+ t.assert.strictEqual(result1.status, 200)
2999
+ const body1 = await result1.text()
3000
+ t.assert.strictEqual(result1.headers.get('content-length'), '' + body1.length)
3001
+ t.assert.deepStrictEqual(JSON.parse(body1), { hello: 'world1' })
3002
+
3003
+ const result2 = await fetch(fastifyServer + '/second')
3004
+ t.assert.ok(result2.ok)
3005
+ t.assert.strictEqual(result2.status, 200)
3006
+ const body2 = await result2.text()
3007
+ t.assert.strictEqual(result2.headers.get('content-length'), '' + body2.length)
3008
+ t.assert.deepStrictEqual(JSON.parse(body2), { hello: 'world12' })
3009
+ })
3010
+
3011
+ test('onRegister hook should be called / 1', (t, testDone) => {
3012
+ t.plan(5)
3013
+ const fastify = Fastify()
3014
+
3015
+ fastify.addHook('onRegister', function (instance, opts, done) {
3016
+ t.assert.ok(this.addHook)
3017
+ t.assert.ok(instance.addHook)
3018
+ t.assert.deepStrictEqual(opts, pluginOpts)
3019
+ t.assert.ok(!done)
3020
+ })
3021
+
3022
+ const pluginOpts = { prefix: 'hello', custom: 'world' }
3023
+ fastify.register((instance, opts, done) => {
3024
+ done()
3025
+ }, pluginOpts)
3026
+
3027
+ fastify.ready(err => {
3028
+ t.assert.ifError(err)
3029
+ testDone()
3030
+ })
3031
+ })
3032
+
3033
+ test('onRegister hook should be called / 2', (t, testDone) => {
3034
+ t.plan(7)
3035
+ const fastify = Fastify()
3036
+
3037
+ fastify.addHook('onRegister', function (instance) {
3038
+ t.assert.ok(this.addHook)
3039
+ t.assert.ok(instance.addHook)
3040
+ })
3041
+
3042
+ fastify.register((instance, opts, done) => {
3043
+ instance.register((instance, opts, done) => {
3044
+ done()
3045
+ })
3046
+ done()
3047
+ })
3048
+
3049
+ fastify.register((instance, opts, done) => {
3050
+ done()
3051
+ })
3052
+
3053
+ fastify.ready(err => {
3054
+ t.assert.ifError(err)
3055
+ testDone()
3056
+ })
3057
+ })
3058
+
3059
+ test('onRegister hook should be called / 3', (t, testDone) => {
3060
+ t.plan(4)
3061
+ const fastify = Fastify()
3062
+
3063
+ fastify.decorate('data', [])
3064
+
3065
+ fastify.addHook('onRegister', instance => {
3066
+ instance.data = instance.data.slice()
3067
+ })
3068
+
3069
+ fastify.register((instance, opts, done) => {
3070
+ instance.data.push(1)
3071
+ instance.register((instance, opts, done) => {
3072
+ instance.data.push(2)
3073
+ t.assert.deepStrictEqual(instance.data, [1, 2])
3074
+ done()
3075
+ })
3076
+ t.assert.deepStrictEqual(instance.data, [1])
3077
+ done()
3078
+ })
3079
+
3080
+ fastify.register((instance, opts, done) => {
3081
+ t.assert.deepStrictEqual(instance.data, [])
3082
+ done()
3083
+ })
3084
+
3085
+ fastify.ready(err => {
3086
+ t.assert.ifError(err)
3087
+ testDone()
3088
+ })
3089
+ })
3090
+
3091
+ test('onRegister hook should be called (encapsulation)', (t, testDone) => {
3092
+ t.plan(1)
3093
+ const fastify = Fastify()
3094
+
3095
+ function plugin (instance, opts, done) {
3096
+ done()
3097
+ }
3098
+ plugin[Symbol.for('skip-override')] = true
3099
+
3100
+ fastify.addHook('onRegister', (instance, opts) => {
3101
+ t.assert.fail('This should not be called')
3102
+ })
3103
+
3104
+ fastify.register(plugin)
3105
+
3106
+ fastify.ready(err => {
3107
+ t.assert.ifError(err)
3108
+ testDone()
3109
+ })
3110
+ })
3111
+
3112
+ test('early termination, onRequest', (t, testDone) => {
3113
+ t.plan(3)
3114
+
3115
+ const app = Fastify()
3116
+
3117
+ app.addHook('onRequest', (req, reply) => {
3118
+ setImmediate(() => reply.send('hello world'))
3119
+ return reply
3120
+ })
3121
+
3122
+ app.get('/', (req, reply) => {
3123
+ t.assert.fail('should not happen')
3124
+ })
3125
+
3126
+ app.inject('/', function (err, res) {
3127
+ t.assert.ifError(err)
3128
+ t.assert.strictEqual(res.statusCode, 200)
3129
+ t.assert.strictEqual(res.body.toString(), 'hello world')
3130
+ testDone()
3131
+ })
3132
+ })
3133
+
3134
+ test('reply.send should throw if undefined error is thrown', (t, testDone) => {
3135
+ /* eslint prefer-promise-reject-errors: ["error", {"allowEmptyReject": true}] */
3136
+
3137
+ t.plan(3)
3138
+ const fastify = Fastify()
3139
+
3140
+ fastify.addHook('onRequest', function (req, reply, done) {
3141
+ return Promise.reject()
3142
+ })
3143
+
3144
+ fastify.get('/', (req, reply) => {
3145
+ reply.send('hello')
3146
+ })
3147
+
3148
+ fastify.inject({
3149
+ method: 'GET',
3150
+ url: '/'
3151
+ }, (err, res) => {
3152
+ t.assert.ifError(err)
3153
+ t.assert.strictEqual(res.statusCode, 500)
3154
+ t.assert.deepStrictEqual(JSON.parse(res.payload), {
3155
+ error: 'Internal Server Error',
3156
+ code: 'FST_ERR_SEND_UNDEFINED_ERR',
3157
+ message: 'Undefined error has occurred',
3158
+ statusCode: 500
3159
+ })
3160
+ testDone()
3161
+ })
3162
+ })
3163
+
3164
+ test('reply.send should throw if undefined error is thrown at preParsing hook', (t, testDone) => {
3165
+ t.plan(3)
3166
+ const fastify = Fastify()
3167
+
3168
+ fastify.addHook('preParsing', function (req, reply, done) {
3169
+ return Promise.reject()
3170
+ })
3171
+
3172
+ fastify.get('/', (req, reply) => {
3173
+ reply.send('hello')
3174
+ })
3175
+
3176
+ fastify.inject({
3177
+ method: 'GET',
3178
+ url: '/'
3179
+ }, (err, res) => {
3180
+ t.assert.ifError(err)
3181
+ t.assert.strictEqual(res.statusCode, 500)
3182
+ t.assert.deepStrictEqual(JSON.parse(res.payload), {
3183
+ error: 'Internal Server Error',
3184
+ code: 'FST_ERR_SEND_UNDEFINED_ERR',
3185
+ message: 'Undefined error has occurred',
3186
+ statusCode: 500
3187
+ })
3188
+ testDone()
3189
+ })
3190
+ })
3191
+
3192
+ test('reply.send should throw if undefined error is thrown at onSend hook', (t, testDone) => {
3193
+ t.plan(3)
3194
+ const fastify = Fastify()
3195
+
3196
+ fastify.addHook('onSend', function (req, reply, done) {
3197
+ return Promise.reject()
3198
+ })
3199
+
3200
+ fastify.get('/', (req, reply) => {
3201
+ reply.send('hello')
3202
+ })
3203
+
3204
+ fastify.inject({
3205
+ method: 'GET',
3206
+ url: '/'
3207
+ }, (err, res) => {
3208
+ t.assert.ifError(err)
3209
+ t.assert.strictEqual(res.statusCode, 500)
3210
+ t.assert.deepStrictEqual(JSON.parse(res.payload), {
3211
+ error: 'Internal Server Error',
3212
+ code: 'FST_ERR_SEND_UNDEFINED_ERR',
3213
+ message: 'Undefined error has occurred',
3214
+ statusCode: 500
3215
+ })
3216
+ testDone()
3217
+ })
3218
+ })
3219
+
3220
+ test('onTimeout should be triggered', async t => {
3221
+ t.plan(4)
3222
+ const fastify = Fastify({ connectionTimeout: 500 })
3223
+ t.after(() => { fastify.close() })
3224
+
3225
+ fastify.addHook('onTimeout', function (req, res, done) {
3226
+ t.assert.ok('called', 'onTimeout')
3227
+ done()
3228
+ })
3229
+
3230
+ fastify.get('/', async (req, reply) => {
3231
+ await reply.send({ hello: 'world' })
3232
+ })
3233
+
3234
+ fastify.get('/timeout', async (req, reply) => {
3235
+ return reply
3236
+ })
3237
+
3238
+ const fastifyServer = await fastify.listen({ port: 0 })
3239
+
3240
+ const result1 = await fetch(fastifyServer)
3241
+ t.assert.ok(result1.ok)
3242
+ t.assert.strictEqual(result1.status, 200)
3243
+
3244
+ await t.assert.rejects(() => fetch(fastifyServer + '/timeout'))
3245
+ })
3246
+
3247
+ test('onTimeout should be triggered and socket _meta is set', async t => {
3248
+ t.plan(4)
3249
+ const fastify = Fastify({ connectionTimeout: 500 })
3250
+ t.after(() => { fastify.close() })
3251
+
3252
+ fastify.addHook('onTimeout', function (req, res, done) {
3253
+ t.assert.ok('called', 'onTimeout')
3254
+ done()
3255
+ })
3256
+
3257
+ fastify.get('/', async (req, reply) => {
3258
+ req.raw.socket._meta = {}
3259
+ return reply.send({ hello: 'world' })
3260
+ })
3261
+
3262
+ fastify.get('/timeout', async (req, reply) => {
3263
+ return reply
3264
+ })
3265
+
3266
+ const fastifyServer = await fastify.listen({ port: 0 })
3267
+
3268
+ const result1 = await fetch(fastifyServer)
3269
+ t.assert.ok(result1.ok)
3270
+ t.assert.strictEqual(result1.status, 200)
3271
+
3272
+ try {
3273
+ await fetch(fastifyServer + '/timeout')
3274
+ t.fail('Should have thrown an error')
3275
+ } catch (err) {
3276
+ t.assert.ok(err instanceof Error)
3277
+ }
3278
+ })
3279
+
3280
+ test('registering invalid hooks should throw an error', async t => {
3281
+ t.plan(3)
3282
+
3283
+ const fastify = Fastify()
3284
+
3285
+ t.assert.throws(() => {
3286
+ fastify.route({
3287
+ method: 'GET',
3288
+ path: '/invalidHook',
3289
+ onRequest: [undefined],
3290
+ async handler () {
3291
+ return 'hello world'
3292
+ }
3293
+ })
3294
+ }, {
3295
+ message: 'onRequest hook should be a function, instead got [object Undefined]'
3296
+ })
3297
+
3298
+ t.assert.throws(() => {
3299
+ fastify.route({
3300
+ method: 'GET',
3301
+ path: '/invalidHook',
3302
+ onRequest: null,
3303
+ async handler () {
3304
+ return 'hello world'
3305
+ }
3306
+ })
3307
+ }, { message: 'onRequest hook should be a function, instead got [object Null]' })
3308
+
3309
+ // undefined is ok
3310
+ fastify.route({
3311
+ method: 'GET',
3312
+ path: '/validhook',
3313
+ onRequest: undefined,
3314
+ async handler () {
3315
+ return 'hello world'
3316
+ }
3317
+ })
3318
+
3319
+ t.assert.throws(() => {
3320
+ fastify.addHook('onRoute', (routeOptions) => {
3321
+ routeOptions.onSend = [undefined]
3322
+ })
3323
+
3324
+ fastify.get('/', function (request, reply) {
3325
+ reply.send('hello world')
3326
+ })
3327
+ }, { message: 'onSend hook should be a function, instead got [object Undefined]' })
3328
+ })
3329
+
3330
+ test('onRequestAbort should be triggered', (t, testDone) => {
3331
+ const fastify = Fastify()
3332
+ let order = 0
3333
+
3334
+ t.plan(7)
3335
+ t.after(() => fastify.close())
3336
+
3337
+ const completion = waitForCb({ steps: 2 })
3338
+ completion.patience.then(testDone)
3339
+
3340
+ fastify.addHook('onRequestAbort', function (req, done) {
3341
+ t.assert.strictEqual(++order, 1, 'called in hook')
3342
+ t.assert.ok(req.pendingResolve, 'request has pendingResolve')
3343
+ req.pendingResolve()
3344
+ completion.stepIn()
3345
+ done()
3346
+ })
3347
+
3348
+ fastify.addHook('onError', function hook (request, reply, error, done) {
3349
+ t.assert.fail('onError should not be called')
3350
+ done()
3351
+ })
3352
+
3353
+ fastify.addHook('onSend', function hook (request, reply, payload, done) {
3354
+ t.assert.strictEqual(payload, '{"hello":"world"}', 'onSend should be called')
3355
+ done(null, payload)
3356
+ })
3357
+
3358
+ fastify.addHook('onResponse', function hook (request, reply, done) {
3359
+ t.assert.fail('onResponse should not be called')
3360
+ done()
3361
+ })
3362
+
3363
+ fastify.route({
3364
+ method: 'GET',
3365
+ path: '/',
3366
+ async handler (request, reply) {
3367
+ t.assert.ok('handler called')
3368
+ let resolvePromise
3369
+ const promise = new Promise(resolve => { resolvePromise = resolve })
3370
+ request.pendingResolve = resolvePromise
3371
+ await promise
3372
+ t.assert.ok('handler promise resolved')
3373
+ return { hello: 'world' }
3374
+ },
3375
+ async onRequestAbort (req) {
3376
+ t.assert.strictEqual(++order, 2, 'called in route')
3377
+ completion.stepIn()
3378
+ }
3379
+ })
3380
+
3381
+ fastify.listen({ port: 0 }, err => {
3382
+ t.assert.ifError(err)
3383
+
3384
+ const socket = connect(fastify.server.address().port)
3385
+
3386
+ socket.write('GET / HTTP/1.1\r\nHost: fastify.test\r\n\r\n')
3387
+
3388
+ sleep(500).then(() => socket.destroy())
3389
+ })
3390
+ })
3391
+
3392
+ test('onRequestAbort should support encapsulation', (t, testDone) => {
3393
+ const fastify = Fastify()
3394
+ let order = 0
3395
+ let child
3396
+
3397
+ t.plan(6)
3398
+ t.after(() => fastify.close())
3399
+
3400
+ const completion = waitForCb({ steps: 2 })
3401
+ completion.patience.then(testDone)
3402
+
3403
+ fastify.addHook('onRequestAbort', function (req, done) {
3404
+ t.assert.strictEqual(++order, 1, 'called in root')
3405
+ t.assert.deepStrictEqual(this.pluginName, child.pluginName)
3406
+ completion.stepIn()
3407
+ done()
3408
+ })
3409
+
3410
+ fastify.register(async function (_child, _) {
3411
+ child = _child
3412
+
3413
+ fastify.addHook('onRequestAbort', async function (req) {
3414
+ t.assert.strictEqual(++order, 2, 'called in child')
3415
+ t.assert.deepStrictEqual(this.pluginName, child.pluginName)
3416
+ completion.stepIn()
3417
+ })
3418
+
3419
+ child.route({
3420
+ method: 'GET',
3421
+ path: '/',
3422
+ async handler (request, reply) {
3423
+ await sleep(1000)
3424
+ return { hello: 'world' }
3425
+ },
3426
+ async onRequestAbort (_req) {
3427
+ t.assert.strictEqual(++order, 3, 'called in route')
3428
+ }
3429
+ })
3430
+ })
3431
+
3432
+ fastify.listen({ port: 0 }, err => {
3433
+ t.assert.ifError(err)
3434
+
3435
+ const socket = connect(fastify.server.address().port)
3436
+
3437
+ socket.write('GET / HTTP/1.1\r\nHost: fastify.test\r\n\r\n')
3438
+
3439
+ sleep(500).then(() => socket.destroy())
3440
+ })
3441
+ })
3442
+
3443
+ test('onRequestAbort should handle errors / 1', (t, testDone) => {
3444
+ const fastify = Fastify()
3445
+
3446
+ t.plan(2)
3447
+ t.after(() => fastify.close())
3448
+
3449
+ fastify.addHook('onRequestAbort', function (req, done) {
3450
+ process.nextTick(() => {
3451
+ t.assert.ok('should pass')
3452
+ testDone()
3453
+ })
3454
+ done(new Error('KABOOM!'))
3455
+ })
3456
+
3457
+ fastify.route({
3458
+ method: 'GET',
3459
+ path: '/',
3460
+ async handler (request, reply) {
3461
+ await sleep(1000)
3462
+ return { hello: 'world' }
3463
+ }
3464
+ })
3465
+
3466
+ fastify.listen({ port: 0 }, err => {
3467
+ t.assert.ifError(err)
3468
+
3469
+ const socket = connect(fastify.server.address().port)
3470
+
3471
+ socket.write('GET / HTTP/1.1\r\nHost: fastify.test\r\n\r\n')
3472
+
3473
+ sleep(500).then(() => socket.destroy())
3474
+ })
3475
+ })
3476
+
3477
+ test('onRequestAbort should handle errors / 2', (t, testDone) => {
3478
+ const fastify = Fastify()
3479
+
3480
+ t.plan(2)
3481
+ t.after(() => fastify.close())
3482
+
3483
+ fastify.addHook('onRequestAbort', function (req, done) {
3484
+ process.nextTick(() => {
3485
+ t.assert.ok('should pass')
3486
+ testDone()
3487
+ })
3488
+ throw new Error('KABOOM!')
3489
+ })
3490
+
3491
+ fastify.route({
3492
+ method: 'GET',
3493
+ path: '/',
3494
+ async handler (request, reply) {
3495
+ await sleep(1000)
3496
+ return { hello: 'world' }
3497
+ }
3498
+ })
3499
+
3500
+ fastify.listen({ port: 0 }, err => {
3501
+ t.assert.ifError(err)
3502
+
3503
+ const socket = connect(fastify.server.address().port)
3504
+
3505
+ socket.write('GET / HTTP/1.1\r\nHost: fastify.test\r\n\r\n')
3506
+
3507
+ sleep(500).then(() => socket.destroy())
3508
+ })
3509
+ })
3510
+
3511
+ test('onRequestAbort should handle async errors / 1', (t, testDone) => {
3512
+ const fastify = Fastify()
3513
+
3514
+ t.plan(2)
3515
+ t.after(() => fastify.close())
3516
+
3517
+ fastify.addHook('onRequestAbort', async function (req) {
3518
+ process.nextTick(() => {
3519
+ t.assert.ok('should pass')
3520
+ testDone()
3521
+ })
3522
+ throw new Error('KABOOM!')
3523
+ })
3524
+
3525
+ fastify.route({
3526
+ method: 'GET',
3527
+ path: '/',
3528
+ async handler (request, reply) {
3529
+ await sleep(1000)
3530
+ return { hello: 'world' }
3531
+ }
3532
+ })
3533
+
3534
+ fastify.listen({ port: 0 }, err => {
3535
+ t.assert.ifError(err)
3536
+
3537
+ const socket = connect(fastify.server.address().port)
3538
+
3539
+ socket.write('GET / HTTP/1.1\r\nHost: fastify.test\r\n\r\n')
3540
+
3541
+ sleep(500).then(() => socket.destroy())
3542
+ })
3543
+ })
3544
+
3545
+ test('onRequestAbort should handle async errors / 2', (t, testDone) => {
3546
+ const fastify = Fastify()
3547
+
3548
+ t.plan(2)
3549
+ t.after(() => fastify.close())
3550
+
3551
+ fastify.addHook('onRequestAbort', async function (req) {
3552
+ process.nextTick(() => {
3553
+ t.assert.ok('should pass')
3554
+ testDone()
3555
+ })
3556
+
3557
+ return Promise.reject()
3558
+ })
3559
+
3560
+ fastify.route({
3561
+ method: 'GET',
3562
+ path: '/',
3563
+ async handler (request, reply) {
3564
+ await sleep(1000)
3565
+ return { hello: 'world' }
3566
+ }
3567
+ })
3568
+
3569
+ fastify.listen({ port: 0 }, err => {
3570
+ t.assert.ifError(err)
3571
+
3572
+ const socket = connect(fastify.server.address().port)
3573
+
3574
+ socket.write('GET / HTTP/1.1\r\nHost: fastify.test\r\n\r\n')
3575
+
3576
+ sleep(500).then(() => socket.destroy())
3577
+ })
3578
+ })