UNPKG

13.9 kBJavaScriptView Raw
1'use strict'
2
3const split = require('split2')
4const sget = require('simple-get').concat
5const Fastify = require('..')
6const fs = require('fs')
7const { promisify } = require('util')
8const sleep = promisify(setTimeout)
9
10function asyncHookTest (t) {
11 const test = t.test
12 test('async hooks', t => {
13 t.plan(21)
14
15 const fastify = Fastify()
16 fastify.addHook('onRequest', async function (request, reply) {
17 await sleep(1)
18 request.test = 'the request is coming'
19 reply.test = 'the reply has come'
20 if (request.raw.method === 'DELETE') {
21 throw new Error('some error')
22 }
23 })
24
25 fastify.addHook('preHandler', async function (request, reply) {
26 await sleep(1)
27 t.is(request.test, 'the request is coming')
28 t.is(reply.test, 'the reply has come')
29 if (request.raw.method === 'HEAD') {
30 throw new Error('some error')
31 }
32 })
33
34 fastify.addHook('onSend', async function (request, reply, payload) {
35 await sleep(1)
36 t.ok('onSend called')
37 })
38
39 fastify.addHook('onResponse', async function (request, reply) {
40 await sleep(1)
41 t.ok('onResponse called')
42 })
43
44 fastify.get('/', function (request, reply) {
45 t.is(request.test, 'the request is coming')
46 t.is(reply.test, 'the reply has come')
47 reply.code(200).send({ hello: 'world' })
48 })
49
50 fastify.head('/', function (req, reply) {
51 reply.code(200).send({ hello: 'world' })
52 })
53
54 fastify.delete('/', function (req, reply) {
55 reply.code(200).send({ hello: 'world' })
56 })
57
58 fastify.listen(0, err => {
59 t.error(err)
60 fastify.server.unref()
61
62 sget({
63 method: 'GET',
64 url: 'http://localhost:' + fastify.server.address().port
65 }, (err, response, body) => {
66 t.error(err)
67 t.strictEqual(response.statusCode, 200)
68 t.strictEqual(response.headers['content-length'], '' + body.length)
69 t.deepEqual(JSON.parse(body), { hello: 'world' })
70 })
71
72 sget({
73 method: 'HEAD',
74 url: 'http://localhost:' + fastify.server.address().port
75 }, (err, response, body) => {
76 t.error(err)
77 t.strictEqual(response.statusCode, 500)
78 })
79
80 sget({
81 method: 'DELETE',
82 url: 'http://localhost:' + fastify.server.address().port
83 }, (err, response, body) => {
84 t.error(err)
85 t.strictEqual(response.statusCode, 500)
86 })
87 })
88 })
89
90 test('modify payload', t => {
91 t.plan(10)
92 const fastify = Fastify()
93 const payload = { hello: 'world' }
94 const modifiedPayload = { hello: 'modified' }
95 const anotherPayload = '"winter is coming"'
96
97 fastify.addHook('onSend', async function (request, reply, thePayload) {
98 t.ok('onSend called')
99 t.deepEqual(JSON.parse(thePayload), payload)
100 return thePayload.replace('world', 'modified')
101 })
102
103 fastify.addHook('onSend', async function (request, reply, thePayload) {
104 t.ok('onSend called')
105 t.deepEqual(JSON.parse(thePayload), modifiedPayload)
106 return anotherPayload
107 })
108
109 fastify.addHook('onSend', async function (request, reply, thePayload) {
110 t.ok('onSend called')
111 t.strictEqual(thePayload, anotherPayload)
112 })
113
114 fastify.get('/', (req, reply) => {
115 reply.send(payload)
116 })
117
118 fastify.inject({
119 method: 'GET',
120 url: '/'
121 }, (err, res) => {
122 t.error(err)
123 t.strictEqual(res.payload, anotherPayload)
124 t.strictEqual(res.statusCode, 200)
125 t.strictEqual(res.headers['content-length'], '18')
126 })
127 })
128
129 test('onRequest hooks should be able to block a request', t => {
130 t.plan(5)
131 const fastify = Fastify()
132
133 fastify.addHook('onRequest', async (req, reply) => {
134 reply.send('hello')
135 })
136
137 fastify.addHook('onRequest', async (req, reply) => {
138 t.fail('this should not be called')
139 })
140
141 fastify.addHook('preHandler', async (req, reply) => {
142 t.fail('this should not be called')
143 })
144
145 fastify.addHook('onSend', async (req, reply, payload) => {
146 t.ok('called')
147 })
148
149 fastify.addHook('onResponse', async (request, reply) => {
150 t.ok('called')
151 })
152
153 fastify.get('/', function (request, reply) {
154 t.fail('we should not be here')
155 })
156
157 fastify.inject({
158 url: '/',
159 method: 'GET'
160 }, (err, res) => {
161 t.error(err)
162 t.is(res.statusCode, 200)
163 t.is(res.payload, 'hello')
164 })
165 })
166
167 test('preHandler hooks should be able to block a request', t => {
168 t.plan(5)
169 const fastify = Fastify()
170
171 fastify.addHook('preHandler', async (req, reply) => {
172 reply.send('hello')
173 })
174
175 fastify.addHook('preHandler', async (req, reply) => {
176 t.fail('this should not be called')
177 })
178
179 fastify.addHook('onSend', async (req, reply, payload) => {
180 t.equal(payload, 'hello')
181 })
182
183 fastify.addHook('onResponse', async (request, reply) => {
184 t.ok('called')
185 })
186
187 fastify.get('/', function (request, reply) {
188 t.fail('we should not be here')
189 })
190
191 fastify.inject({
192 url: '/',
193 method: 'GET'
194 }, (err, res) => {
195 t.error(err)
196 t.is(res.statusCode, 200)
197 t.is(res.payload, 'hello')
198 })
199 })
200
201 test('preValidation hooks should be able to block a request', t => {
202 t.plan(5)
203 const fastify = Fastify()
204
205 fastify.addHook('preValidation', async (req, reply) => {
206 reply.send('hello')
207 })
208
209 fastify.addHook('preValidation', async (req, reply) => {
210 t.fail('this should not be called')
211 })
212
213 fastify.addHook('onSend', async (req, reply, payload) => {
214 t.equal(payload, 'hello')
215 })
216
217 fastify.addHook('onResponse', async (request, reply) => {
218 t.ok('called')
219 })
220
221 fastify.get('/', function (request, reply) {
222 t.fail('we should not be here')
223 })
224
225 fastify.inject({
226 url: '/',
227 method: 'GET'
228 }, (err, res) => {
229 t.error(err)
230 t.is(res.statusCode, 200)
231 t.is(res.payload, 'hello')
232 })
233 })
234
235 test('preValidation hooks should be able to block a request with async onSend', t => {
236 t.plan(5)
237 const fastify = Fastify()
238
239 fastify.addHook('preValidation', async (req, reply) => {
240 reply.send('hello')
241 })
242
243 fastify.addHook('onSend', async (req, reply, payload) => {
244 await sleep(10)
245 t.equal(payload, 'hello')
246 })
247
248 fastify.addHook('preHandler', async (request, reply) => {
249 t.fail('we should not be here')
250 })
251
252 fastify.addHook('onResponse', async (request, reply) => {
253 t.ok('called')
254 })
255
256 fastify.post('/', {
257 schema: {
258 body: {
259 type: 'object',
260 properties: {
261 hello: {
262 type: 'string'
263 }
264 },
265 required: ['hello']
266 }
267 }
268 }, function (request, reply) {
269 t.fail('we should not be here')
270 })
271
272 fastify.inject({
273 url: '/',
274 method: 'POST'
275 }, (err, res) => {
276 t.error(err)
277 t.is(res.statusCode, 200)
278 t.is(res.payload, 'hello')
279 })
280 })
281
282 test('preSerialization hooks should be able to modify the payload', t => {
283 t.plan(3)
284 const fastify = Fastify()
285
286 fastify.addHook('preSerialization', async (req, reply, payload) => {
287 return { hello: 'another world' }
288 })
289
290 fastify.get('/', function (request, reply) {
291 reply.send({ hello: 'world' })
292 })
293
294 fastify.inject({
295 url: '/',
296 method: 'GET'
297 }, (err, res) => {
298 t.error(err)
299 t.is(res.statusCode, 200)
300 t.deepEqual(JSON.parse(res.payload), { hello: 'another world' })
301 })
302 })
303
304 test('preSerialization hooks should handle errors', t => {
305 t.plan(3)
306 const fastify = Fastify()
307
308 fastify.addHook('preSerialization', async (req, reply, payload) => {
309 throw new Error('kaboom')
310 })
311
312 fastify.get('/', function (request, reply) {
313 reply.send({ hello: 'world' })
314 })
315
316 fastify.inject({
317 url: '/',
318 method: 'GET'
319 }, (err, res) => {
320 t.error(err)
321 t.is(res.statusCode, 500)
322 t.deepEqual(JSON.parse(res.payload), { error: 'Internal Server Error', message: 'kaboom', statusCode: 500 })
323 })
324 })
325
326 test('onRequest hooks should be able to block a request (last hook)', t => {
327 t.plan(5)
328 const fastify = Fastify()
329
330 fastify.addHook('onRequest', async (req, reply) => {
331 reply.send('hello')
332 })
333
334 fastify.addHook('preHandler', async (req, reply) => {
335 t.fail('this should not be called')
336 })
337
338 fastify.addHook('onSend', async (req, reply, payload) => {
339 t.ok('called')
340 })
341
342 fastify.addHook('onResponse', async (request, reply) => {
343 t.ok('called')
344 })
345
346 fastify.get('/', function (request, reply) {
347 t.fail('we should not be here')
348 })
349
350 fastify.inject({
351 url: '/',
352 method: 'GET'
353 }, (err, res) => {
354 t.error(err)
355 t.is(res.statusCode, 200)
356 t.is(res.payload, 'hello')
357 })
358 })
359
360 test('preHandler hooks should be able to block a request (last hook)', t => {
361 t.plan(5)
362 const fastify = Fastify()
363
364 fastify.addHook('preHandler', async (req, reply) => {
365 reply.send('hello')
366 })
367
368 fastify.addHook('onSend', async (req, reply, payload) => {
369 t.equal(payload, 'hello')
370 })
371
372 fastify.addHook('onResponse', async (request, reply) => {
373 t.ok('called')
374 })
375
376 fastify.get('/', function (request, reply) {
377 t.fail('we should not be here')
378 })
379
380 fastify.inject({
381 url: '/',
382 method: 'GET'
383 }, (err, res) => {
384 t.error(err)
385 t.is(res.statusCode, 200)
386 t.is(res.payload, 'hello')
387 })
388 })
389
390 test('preHandler hooks should be able to block a request (last hook) with a delay in onSend', t => {
391 t.plan(5)
392 const fastify = Fastify()
393
394 fastify.addHook('preHandler', async (req, reply) => {
395 reply.send('hello')
396 })
397
398 fastify.addHook('onSend', async (req, reply, payload) => {
399 await sleep(10)
400 t.equal(payload, 'hello')
401 })
402
403 fastify.addHook('onResponse', async (request, reply) => {
404 t.ok('called')
405 })
406
407 fastify.get('/', function (request, reply) {
408 t.fail('we should not be here')
409 })
410
411 fastify.inject({
412 url: '/',
413 method: 'GET'
414 }, (err, res) => {
415 t.error(err)
416 t.is(res.statusCode, 200)
417 t.is(res.payload, 'hello')
418 })
419 })
420
421 test('onRequest respond with a stream', t => {
422 t.plan(4)
423 const fastify = Fastify()
424
425 fastify.addHook('onRequest', async (req, reply) => {
426 return new Promise((resolve, reject) => {
427 const stream = fs.createReadStream(process.cwd() + '/test/stream.test.js', 'utf8')
428 // stream.pipe(res)
429 // res.once('finish', resolve)
430 reply.send(stream)
431 reply.res.once('finish', () => resolve())
432 })
433 })
434
435 fastify.addHook('onRequest', async (req, res) => {
436 t.fail('this should not be called')
437 })
438
439 fastify.addHook('preHandler', async (req, reply) => {
440 t.fail('this should not be called')
441 })
442
443 fastify.addHook('onSend', async (req, reply, payload) => {
444 t.ok('called')
445 })
446
447 fastify.addHook('onResponse', async (request, reply) => {
448 t.ok('called')
449 })
450
451 fastify.get('/', function (request, reply) {
452 t.fail('we should not be here')
453 })
454
455 fastify.inject({
456 url: '/',
457 method: 'GET'
458 }, (err, res) => {
459 t.error(err)
460 t.is(res.statusCode, 200)
461 })
462 })
463
464 test('preHandler respond with a stream', t => {
465 t.plan(7)
466 const fastify = Fastify()
467
468 fastify.addHook('onRequest', async (req, res) => {
469 t.ok('called')
470 })
471
472 // we are calling `reply.send` inside the `preHandler` hook with a stream,
473 // this triggers the `onSend` hook event if `preHanlder` has not yet finished
474 const order = [1, 2]
475
476 fastify.addHook('preHandler', async (req, reply) => {
477 return new Promise((resolve, reject) => {
478 const stream = fs.createReadStream(process.cwd() + '/test/stream.test.js', 'utf8')
479 reply.send(stream)
480 reply.res.once('finish', () => {
481 t.is(order.shift(), 2)
482 resolve()
483 })
484 })
485 })
486
487 fastify.addHook('preHandler', async (req, reply) => {
488 t.fail('this should not be called')
489 })
490
491 fastify.addHook('onSend', async (req, reply, payload) => {
492 t.is(order.shift(), 1)
493 t.is(typeof payload.pipe, 'function')
494 })
495
496 fastify.addHook('onResponse', async (request, reply) => {
497 t.ok('called')
498 })
499
500 fastify.get('/', function (request, reply) {
501 t.fail('we should not be here')
502 })
503
504 fastify.inject({
505 url: '/',
506 method: 'GET'
507 }, (err, res) => {
508 t.error(err)
509 t.is(res.statusCode, 200)
510 })
511 })
512
513 test('Should log a warning if is an async function with `next`', t => {
514 t.test('3 arguments', t => {
515 t.plan(3)
516 const stream = split(JSON.parse)
517 const fastify = Fastify({
518 logger: { stream }
519 })
520
521 stream.on('data', line => {
522 t.strictEqual(line.level, 40)
523 t.true(line.msg.startsWith("Async function has too many arguments. Async hooks should not use the 'next' argument."))
524 t.true(/test(\\|\/)hooks-async\.js/.test(line.msg))
525 })
526
527 fastify.addHook('onRequest', async (req, reply, next) => {})
528 })
529
530 t.test('4 arguments', t => {
531 t.plan(6)
532 const stream = split(JSON.parse)
533 const fastify = Fastify({
534 logger: { stream }
535 })
536
537 stream.on('data', line => {
538 t.strictEqual(line.level, 40)
539 t.true(line.msg.startsWith("Async function has too many arguments. Async hooks should not use the 'next' argument."))
540 t.true(/test(\\|\/)hooks-async\.js/.test(line.msg))
541 })
542
543 fastify.addHook('onSend', async (req, reply, payload, next) => {})
544 fastify.addHook('preSerialization', async (req, reply, payload, next) => {})
545 })
546
547 t.end()
548 })
549}
550
551module.exports = asyncHookTest