UNPKG

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