You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					627 lines
				
				14 KiB
			
		
		
			
		
	
	
					627 lines
				
				14 KiB
			| 
											3 years ago
										 | 'use strict' | ||
|  | 
 | ||
|  | const t = require('tap') | ||
|  | const test = t.test | ||
|  | const net = require('net') | ||
|  | const Fastify = require('..') | ||
|  | const statusCodes = require('http').STATUS_CODES | ||
|  | const split = require('split2') | ||
|  | const fs = require('fs') | ||
|  | const path = require('path') | ||
|  | 
 | ||
|  | const codes = Object.keys(statusCodes) | ||
|  | codes.forEach(code => { | ||
|  |   if (Number(code) >= 400) helper(code) | ||
|  | }) | ||
|  | 
 | ||
|  | function helper (code) { | ||
|  |   test('Reply error handling - code: ' + code, t => { | ||
|  |     t.plan(4) | ||
|  |     const fastify = Fastify() | ||
|  |     const err = new Error('winter is coming') | ||
|  | 
 | ||
|  |     fastify.get('/', (req, reply) => { | ||
|  |       reply | ||
|  |         .code(Number(code)) | ||
|  |         .send(err) | ||
|  |     }) | ||
|  | 
 | ||
|  |     fastify.inject({ | ||
|  |       method: 'GET', | ||
|  |       url: '/' | ||
|  |     }, (error, res) => { | ||
|  |       t.error(error) | ||
|  |       t.equal(res.statusCode, Number(code)) | ||
|  |       t.equal(res.headers['content-type'], 'application/json; charset=utf-8') | ||
|  |       t.same( | ||
|  |         { | ||
|  |           error: statusCodes[code], | ||
|  |           message: err.message, | ||
|  |           statusCode: Number(code) | ||
|  |         }, | ||
|  |         JSON.parse(res.payload) | ||
|  |       ) | ||
|  |     }) | ||
|  |   }) | ||
|  | } | ||
|  | 
 | ||
|  | test('preHandler hook error handling with external code', t => { | ||
|  |   t.plan(3) | ||
|  |   const fastify = Fastify() | ||
|  |   const err = new Error('winter is coming') | ||
|  | 
 | ||
|  |   fastify.addHook('preHandler', (req, reply, done) => { | ||
|  |     reply.code(400) | ||
|  |     done(err) | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.get('/', () => {}) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     method: 'GET', | ||
|  |     url: '/' | ||
|  |   }, (error, res) => { | ||
|  |     t.error(error) | ||
|  |     t.equal(res.statusCode, 400) | ||
|  |     t.same( | ||
|  |       { | ||
|  |         error: statusCodes['400'], | ||
|  |         message: err.message, | ||
|  |         statusCode: 400 | ||
|  |       }, | ||
|  |       JSON.parse(res.payload) | ||
|  |     ) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('onRequest hook error handling with external done', t => { | ||
|  |   t.plan(3) | ||
|  |   const fastify = Fastify() | ||
|  |   const err = new Error('winter is coming') | ||
|  | 
 | ||
|  |   fastify.addHook('onRequest', (req, reply, done) => { | ||
|  |     reply.code(400) | ||
|  |     done(err) | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.get('/', () => {}) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     method: 'GET', | ||
|  |     url: '/' | ||
|  |   }, (error, res) => { | ||
|  |     t.error(error) | ||
|  |     t.equal(res.statusCode, 400) | ||
|  |     t.same( | ||
|  |       { | ||
|  |         error: statusCodes['400'], | ||
|  |         message: err.message, | ||
|  |         statusCode: 400 | ||
|  |       }, | ||
|  |       JSON.parse(res.payload) | ||
|  |     ) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('Should reply 400 on client error', t => { | ||
|  |   t.plan(2) | ||
|  | 
 | ||
|  |   const fastify = Fastify() | ||
|  |   fastify.listen(0, err => { | ||
|  |     t.error(err) | ||
|  | 
 | ||
|  |     const client = net.connect(fastify.server.address().port) | ||
|  |     client.end('oooops!') | ||
|  | 
 | ||
|  |     let chunks = '' | ||
|  |     client.on('data', chunk => { | ||
|  |       chunks += chunk | ||
|  |     }) | ||
|  | 
 | ||
|  |     client.once('end', () => { | ||
|  |       const body = JSON.stringify({ | ||
|  |         error: 'Bad Request', | ||
|  |         message: 'Client Error', | ||
|  |         statusCode: 400 | ||
|  |       }) | ||
|  |       t.equal(`HTTP/1.1 400 Bad Request\r\nContent-Length: ${body.length}\r\nContent-Type: application/json\r\n\r\n${body}`, chunks) | ||
|  |       fastify.close() | ||
|  |     }) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('Should set the response from client error handler', t => { | ||
|  |   t.plan(5) | ||
|  | 
 | ||
|  |   const responseBody = JSON.stringify({ | ||
|  |     error: 'Ended Request', | ||
|  |     message: 'Serious Client Error', | ||
|  |     statusCode: 400 | ||
|  |   }) | ||
|  |   const response = `HTTP/1.1 400 Bad Request\r\nContent-Length: ${responseBody.length}\r\nContent-Type: application/json; charset=utf-8\r\n\r\n${responseBody}` | ||
|  | 
 | ||
|  |   function clientErrorHandler (err, socket) { | ||
|  |     t.type(err, Error) | ||
|  | 
 | ||
|  |     this.log.warn({ err }, 'Handled client error') | ||
|  |     socket.end(response) | ||
|  |   } | ||
|  | 
 | ||
|  |   const logStream = split(JSON.parse) | ||
|  |   const fastify = Fastify({ | ||
|  |     clientErrorHandler, | ||
|  |     logger: { | ||
|  |       stream: logStream, | ||
|  |       level: 'warn' | ||
|  |     } | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.listen(0, err => { | ||
|  |     t.error(err) | ||
|  | 
 | ||
|  |     const client = net.connect(fastify.server.address().port) | ||
|  |     client.end('oooops!') | ||
|  | 
 | ||
|  |     let chunks = '' | ||
|  |     client.on('data', chunk => { | ||
|  |       chunks += chunk | ||
|  |     }) | ||
|  | 
 | ||
|  |     client.once('end', () => { | ||
|  |       t.equal(response, chunks) | ||
|  |       fastify.close() | ||
|  |     }) | ||
|  |   }) | ||
|  | 
 | ||
|  |   logStream.once('data', line => { | ||
|  |     t.equal('Handled client error', line.msg) | ||
|  |     t.equal(40, line.level, 'Log level is not warn') | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('Error instance sets HTTP status code', t => { | ||
|  |   t.plan(3) | ||
|  |   const fastify = Fastify() | ||
|  |   const err = new Error('winter is coming') | ||
|  |   err.statusCode = 418 | ||
|  | 
 | ||
|  |   fastify.get('/', () => { | ||
|  |     return Promise.reject(err) | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     method: 'GET', | ||
|  |     url: '/' | ||
|  |   }, (error, res) => { | ||
|  |     t.error(error) | ||
|  |     t.equal(res.statusCode, 418) | ||
|  |     t.same( | ||
|  |       { | ||
|  |         error: statusCodes['418'], | ||
|  |         message: err.message, | ||
|  |         statusCode: 418 | ||
|  |       }, | ||
|  |       JSON.parse(res.payload) | ||
|  |     ) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('Error status code below 400 defaults to 500', t => { | ||
|  |   t.plan(3) | ||
|  |   const fastify = Fastify() | ||
|  |   const err = new Error('winter is coming') | ||
|  |   err.statusCode = 399 | ||
|  | 
 | ||
|  |   fastify.get('/', () => { | ||
|  |     return Promise.reject(err) | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     method: 'GET', | ||
|  |     url: '/' | ||
|  |   }, (error, res) => { | ||
|  |     t.error(error) | ||
|  |     t.equal(res.statusCode, 500) | ||
|  |     t.same( | ||
|  |       { | ||
|  |         error: statusCodes['500'], | ||
|  |         message: err.message, | ||
|  |         statusCode: 500 | ||
|  |       }, | ||
|  |       JSON.parse(res.payload) | ||
|  |     ) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('Error.status property support', t => { | ||
|  |   t.plan(3) | ||
|  |   const fastify = Fastify() | ||
|  |   const err = new Error('winter is coming') | ||
|  |   err.status = 418 | ||
|  | 
 | ||
|  |   fastify.get('/', () => { | ||
|  |     return Promise.reject(err) | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     method: 'GET', | ||
|  |     url: '/' | ||
|  |   }, (error, res) => { | ||
|  |     t.error(error) | ||
|  |     t.equal(res.statusCode, 418) | ||
|  |     t.same( | ||
|  |       { | ||
|  |         error: statusCodes['418'], | ||
|  |         message: err.message, | ||
|  |         statusCode: 418 | ||
|  |       }, | ||
|  |       JSON.parse(res.payload) | ||
|  |     ) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('Support rejection with values that are not Error instances', t => { | ||
|  |   const objs = [ | ||
|  |     0, | ||
|  |     '', | ||
|  |     [], | ||
|  |     {}, | ||
|  |     null, | ||
|  |     undefined, | ||
|  |     123, | ||
|  |     'abc', | ||
|  |     new RegExp(), | ||
|  |     new Date(), | ||
|  |     new Uint8Array() | ||
|  |   ] | ||
|  |   t.plan(objs.length) | ||
|  |   for (const nonErr of objs) { | ||
|  |     t.test('Type: ' + typeof nonErr, t => { | ||
|  |       t.plan(4) | ||
|  |       const fastify = Fastify() | ||
|  | 
 | ||
|  |       fastify.get('/', () => { | ||
|  |         return Promise.reject(nonErr) | ||
|  |       }) | ||
|  | 
 | ||
|  |       fastify.setErrorHandler((err, request, reply) => { | ||
|  |         if (typeof err === 'object') { | ||
|  |           t.same(err, nonErr) | ||
|  |         } else { | ||
|  |           t.equal(err, nonErr) | ||
|  |         } | ||
|  |         reply.send('error') | ||
|  |       }) | ||
|  | 
 | ||
|  |       fastify.inject({ | ||
|  |         method: 'GET', | ||
|  |         url: '/' | ||
|  |       }, (error, res) => { | ||
|  |         t.error(error) | ||
|  |         t.equal(res.statusCode, 500) | ||
|  |         t.equal(res.payload, 'error') | ||
|  |       }) | ||
|  |     }) | ||
|  |   } | ||
|  | }) | ||
|  | 
 | ||
|  | test('invalid schema - ajv', t => { | ||
|  |   t.plan(4) | ||
|  | 
 | ||
|  |   const fastify = Fastify() | ||
|  |   fastify.get('/', { | ||
|  |     schema: { | ||
|  |       querystring: { | ||
|  |         type: 'object', | ||
|  |         properties: { | ||
|  |           id: { type: 'number' } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   }, (req, reply) => { | ||
|  |     t.fail('we should not be here') | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.setErrorHandler((err, request, reply) => { | ||
|  |     t.ok(Array.isArray(err.validation)) | ||
|  |     reply.send('error') | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     url: '/?id=abc', | ||
|  |     method: 'GET' | ||
|  |   }, (err, res) => { | ||
|  |     t.error(err) | ||
|  |     t.equal(res.statusCode, 400) | ||
|  |     t.equal(res.payload, 'error') | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('should set the status code and the headers from the error object (from route handler)', t => { | ||
|  |   t.plan(4) | ||
|  |   const fastify = Fastify() | ||
|  | 
 | ||
|  |   fastify.get('/', (req, reply) => { | ||
|  |     const error = new Error('kaboom') | ||
|  |     error.headers = { hello: 'world' } | ||
|  |     error.statusCode = 400 | ||
|  |     reply.send(error) | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     url: '/', | ||
|  |     method: 'GET' | ||
|  |   }, (err, res) => { | ||
|  |     t.error(err) | ||
|  |     t.equal(res.statusCode, 400) | ||
|  |     t.equal(res.headers.hello, 'world') | ||
|  |     t.same(JSON.parse(res.payload), { | ||
|  |       error: 'Bad Request', | ||
|  |       message: 'kaboom', | ||
|  |       statusCode: 400 | ||
|  |     }) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('should set the status code and the headers from the error object (from custom error handler)', t => { | ||
|  |   t.plan(6) | ||
|  |   const fastify = Fastify() | ||
|  | 
 | ||
|  |   fastify.get('/', (req, reply) => { | ||
|  |     const error = new Error('ouch') | ||
|  |     error.statusCode = 401 | ||
|  |     reply.send(error) | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.setErrorHandler((err, request, reply) => { | ||
|  |     t.equal(err.message, 'ouch') | ||
|  |     t.equal(reply.raw.statusCode, 401) | ||
|  |     const error = new Error('kaboom') | ||
|  |     error.headers = { hello: 'world' } | ||
|  |     error.statusCode = 400 | ||
|  |     reply.send(error) | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     url: '/', | ||
|  |     method: 'GET' | ||
|  |   }, (err, res) => { | ||
|  |     t.error(err) | ||
|  |     t.equal(res.statusCode, 400) | ||
|  |     t.equal(res.headers.hello, 'world') | ||
|  |     t.same(JSON.parse(res.payload), { | ||
|  |       error: 'Bad Request', | ||
|  |       message: 'kaboom', | ||
|  |       statusCode: 400 | ||
|  |     }) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | // Issue 595 https://github.com/fastify/fastify/issues/595
 | ||
|  | test('\'*\' should throw an error due to serializer can not handle the payload type', t => { | ||
|  |   t.plan(3) | ||
|  |   const fastify = Fastify() | ||
|  | 
 | ||
|  |   fastify.get('/', (req, reply) => { | ||
|  |     reply.type('text/html') | ||
|  |     try { | ||
|  |       reply.send({}) | ||
|  |     } catch (err) { | ||
|  |       t.type(err, TypeError) | ||
|  |       t.equal(err.code, 'FST_ERR_REP_INVALID_PAYLOAD_TYPE') | ||
|  |       t.equal(err.message, "Attempted to send payload of invalid type 'object'. Expected a string or Buffer.") | ||
|  |     } | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     url: '/', | ||
|  |     method: 'GET' | ||
|  |   }, (e, res) => { | ||
|  |     t.fail('should not be called') | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('should throw an error if the custom serializer does not serialize the payload to a valid type', t => { | ||
|  |   t.plan(3) | ||
|  |   const fastify = Fastify() | ||
|  | 
 | ||
|  |   fastify.get('/', (req, reply) => { | ||
|  |     try { | ||
|  |       reply | ||
|  |         .type('text/html') | ||
|  |         .serializer(payload => payload) | ||
|  |         .send({}) | ||
|  |     } catch (err) { | ||
|  |       t.type(err, TypeError) | ||
|  |       t.equal(err.code, 'FST_ERR_REP_INVALID_PAYLOAD_TYPE') | ||
|  |       t.equal(err.message, "Attempted to send payload of invalid type 'object'. Expected a string or Buffer.") | ||
|  |     } | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     url: '/', | ||
|  |     method: 'GET' | ||
|  |   }, (e, res) => { | ||
|  |     t.fail('should not be called') | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | // Issue 2078 https://github.com/fastify/fastify/issues/2078
 | ||
|  | // Supported error code list: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
 | ||
|  | const invalidErrorCodes = [ | ||
|  |   undefined, | ||
|  |   null, | ||
|  |   'error_code', | ||
|  |   700 // out of the 100-600 range
 | ||
|  | ] | ||
|  | invalidErrorCodes.forEach((invalidCode) => { | ||
|  |   test(`should throw error if error code is ${invalidCode}`, t => { | ||
|  |     t.plan(2) | ||
|  |     const fastify = Fastify() | ||
|  |     fastify.get('/', (request, reply) => { | ||
|  |       try { | ||
|  |         return reply.code(invalidCode).send('You should not read this') | ||
|  |       } catch (err) { | ||
|  |         t.equal(err.code, 'FST_ERR_BAD_STATUS_CODE') | ||
|  |         t.equal(err.message, 'Called reply with an invalid status code: ' + invalidCode) | ||
|  |       } | ||
|  |     }) | ||
|  |     fastify.inject({ | ||
|  |       url: '/', | ||
|  |       method: 'GET' | ||
|  |     }, (e, res) => { | ||
|  |       t.fail('should not be called') | ||
|  |     }) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('status code should be set to 500 and return an error json payload if route handler throws any non Error object expression', async t => { | ||
|  |   t.plan(2) | ||
|  |   const fastify = Fastify() | ||
|  | 
 | ||
|  |   fastify.get('/', () => { | ||
|  |     /* eslint-disable-next-line */ | ||
|  |     throw { foo: 'bar' } | ||
|  |   }) | ||
|  | 
 | ||
|  |   // ----
 | ||
|  |   const reply = await fastify.inject({ method: 'GET', url: '/' }) | ||
|  |   t.equal(reply.statusCode, 500) | ||
|  |   t.equal(JSON.parse(reply.body).foo, 'bar') | ||
|  | }) | ||
|  | 
 | ||
|  | test('should preserve the status code set by the user if an expression is thrown in a sync route', async t => { | ||
|  |   t.plan(2) | ||
|  |   const fastify = Fastify() | ||
|  | 
 | ||
|  |   fastify.get('/', (_, rep) => { | ||
|  |     rep.status(501) | ||
|  | 
 | ||
|  |     /* eslint-disable-next-line */ | ||
|  |     throw { foo: 'bar' } | ||
|  |   }) | ||
|  | 
 | ||
|  |   // ----
 | ||
|  |   const reply = await fastify.inject({ method: 'GET', url: '/' }) | ||
|  |   t.equal(reply.statusCode, 501) | ||
|  |   t.equal(JSON.parse(reply.body).foo, 'bar') | ||
|  | }) | ||
|  | 
 | ||
|  | test('should trigger error handlers if a sync route throws any non-error object', async t => { | ||
|  |   t.plan(3) | ||
|  | 
 | ||
|  |   const fastify = Fastify() | ||
|  | 
 | ||
|  |   fastify.get('/', () => { | ||
|  |     /* eslint-disable-next-line */ | ||
|  |     throw { foo: 'bar' } | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.setErrorHandler(async (error) => { | ||
|  |     t.ok(error) | ||
|  |     return error | ||
|  |   }) | ||
|  | 
 | ||
|  |   // ----
 | ||
|  |   const reply = await fastify.inject({ method: 'GET', url: '/' }) | ||
|  |   t.equal(reply.statusCode, 500) | ||
|  |   t.equal(JSON.parse(reply.body).foo, 'bar') | ||
|  | }) | ||
|  | 
 | ||
|  | test('setting content-type on reply object should not hang the server case 1', t => { | ||
|  |   t.plan(2) | ||
|  |   const fastify = Fastify() | ||
|  | 
 | ||
|  |   fastify.get('/', (req, reply) => { | ||
|  |     reply | ||
|  |       .code(200) | ||
|  |       .headers({ 'content-type': 'text/plain; charset=utf-32' }) | ||
|  |       .send(JSON.stringify({ bar: 'foo', baz: 'foobar' })) | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     url: '/', | ||
|  |     method: 'GET' | ||
|  |   }, (err, res) => { | ||
|  |     t.error(err) | ||
|  |     t.equal(res.statusCode, 200) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('setting content-type on reply object should not hang the server case 2', async t => { | ||
|  |   t.plan(1) | ||
|  |   const fastify = Fastify() | ||
|  | 
 | ||
|  |   fastify.get('/', (req, reply) => { | ||
|  |     reply | ||
|  |       .code(200) | ||
|  |       .headers({ 'content-type': 'text/plain; charset=utf-8' }) | ||
|  |       .send({ bar: 'foo', baz: 'foobar' }) | ||
|  |   }) | ||
|  | 
 | ||
|  |   try { | ||
|  |     await fastify.listen(0) | ||
|  |     const res = await fastify.inject({ | ||
|  |       url: '/', | ||
|  |       method: 'GET' | ||
|  |     }) | ||
|  |     t.same({ | ||
|  |       error: 'Internal Server Error', | ||
|  |       message: 'Attempted to send payload of invalid type \'object\'. Expected a string or Buffer.', | ||
|  |       statusCode: 500, | ||
|  |       code: 'FST_ERR_REP_INVALID_PAYLOAD_TYPE' | ||
|  |     }, | ||
|  |     res.json()) | ||
|  |   } catch (error) { | ||
|  |     t.error(error) | ||
|  |   } finally { | ||
|  |     await fastify.close() | ||
|  |   } | ||
|  | }) | ||
|  | 
 | ||
|  | test('setting content-type on reply object should not hang the server case 3', t => { | ||
|  |   t.plan(2) | ||
|  |   const fastify = Fastify() | ||
|  | 
 | ||
|  |   fastify.get('/', (req, reply) => { | ||
|  |     reply | ||
|  |       .code(200) | ||
|  |       .headers({ 'content-type': 'application/json' }) | ||
|  |       .send({ bar: 'foo', baz: 'foobar' }) | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     url: '/', | ||
|  |     method: 'GET' | ||
|  |   }, (err, res) => { | ||
|  |     t.error(err) | ||
|  |     t.equal(res.statusCode, 200) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('pipe stream inside error handler should not cause error', t => { | ||
|  |   t.plan(3) | ||
|  |   const location = path.join(__dirname, '..', 'package.json') | ||
|  |   const json = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json')).toString('utf8')) | ||
|  | 
 | ||
|  |   const fastify = Fastify() | ||
|  | 
 | ||
|  |   fastify.setErrorHandler((_error, _request, reply) => { | ||
|  |     const stream = fs.createReadStream(location) | ||
|  |     reply.code(400).type('application/json; charset=utf-8').send(stream) | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.get('/', (request, reply) => { | ||
|  |     throw new Error('This is an error.') | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     url: '/', | ||
|  |     method: 'GET' | ||
|  |   }, (err, res) => { | ||
|  |     t.error(err) | ||
|  |     t.equal(res.statusCode, 400) | ||
|  |     t.same(JSON.parse(res.payload), json) | ||
|  |   }) | ||
|  | }) |