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.
		
		
		
		
		
			
		
			
				
					282 lines
				
				6.8 KiB
			
		
		
			
		
	
	
					282 lines
				
				6.8 KiB
			| 
											3 years ago
										 | 'use strict' | ||
|  | 
 | ||
|  | const { test } = require('tap') | ||
|  | const semver = require('semver') | ||
|  | const handleRequest = require('../../lib/handleRequest') | ||
|  | const internals = require('../../lib/handleRequest')[Symbol.for('internals')] | ||
|  | const Request = require('../../lib/request') | ||
|  | const Reply = require('../../lib/reply') | ||
|  | const buildSchema = require('../../lib/validation').compileSchemasForValidation | ||
|  | const sget = require('simple-get').concat | ||
|  | 
 | ||
|  | const Ajv = require('ajv') | ||
|  | const ajv = new Ajv({ coerceTypes: true }) | ||
|  | 
 | ||
|  | function schemaValidator ({ schema, method, url, httpPart }) { | ||
|  |   const validateFuncion = ajv.compile(schema) | ||
|  |   const fn = function (body) { | ||
|  |     const isOk = validateFuncion(body) | ||
|  |     if (isOk) return | ||
|  |     return false | ||
|  |   } | ||
|  |   fn.errors = [] | ||
|  |   return fn | ||
|  | } | ||
|  | 
 | ||
|  | test('handleRequest function - sent reply', t => { | ||
|  |   t.plan(1) | ||
|  |   const request = {} | ||
|  |   const reply = { sent: true } | ||
|  |   const res = handleRequest(null, request, reply) | ||
|  |   t.equal(res, undefined) | ||
|  | }) | ||
|  | 
 | ||
|  | test('handleRequest function - invoke with error', t => { | ||
|  |   t.plan(1) | ||
|  |   const request = {} | ||
|  |   const reply = {} | ||
|  |   reply.send = (err) => t.equal(err.message, 'Kaboom') | ||
|  |   handleRequest(new Error('Kaboom'), request, reply) | ||
|  | }) | ||
|  | 
 | ||
|  | test('handler function - invalid schema', t => { | ||
|  |   t.plan(2) | ||
|  |   const res = {} | ||
|  |   res.end = () => { | ||
|  |     t.equal(res.statusCode, 400) | ||
|  |     t.pass() | ||
|  |   } | ||
|  |   res.writeHead = () => {} | ||
|  |   res.log = { error: () => {}, info: () => {} } | ||
|  |   const context = { | ||
|  |     config: { | ||
|  |       method: 'GET', | ||
|  |       url: '/an-url' | ||
|  |     }, | ||
|  |     schema: { | ||
|  |       body: { | ||
|  |         type: 'object', | ||
|  |         properties: { | ||
|  |           hello: { type: 'number' } | ||
|  |         } | ||
|  |       } | ||
|  |     }, | ||
|  |     handler: () => {}, | ||
|  |     Reply, | ||
|  |     Request, | ||
|  |     preValidation: [], | ||
|  |     preHandler: [], | ||
|  |     onSend: [], | ||
|  |     onError: [], | ||
|  |     attachValidation: false, | ||
|  |     schemaErrorFormatter: () => new Error() | ||
|  |   } | ||
|  |   buildSchema(context, schemaValidator) | ||
|  |   const request = { | ||
|  |     body: { hello: 'world' }, | ||
|  |     context | ||
|  |   } | ||
|  |   internals.handler(request, new Reply(res, request)) | ||
|  | }) | ||
|  | 
 | ||
|  | test('handler function - reply', t => { | ||
|  |   t.plan(3) | ||
|  |   const res = {} | ||
|  |   res.end = () => { | ||
|  |     t.equal(res.statusCode, 204) | ||
|  |     t.pass() | ||
|  |   } | ||
|  |   res.writeHead = () => {} | ||
|  |   const context = { | ||
|  |     handler: (req, reply) => { | ||
|  |       t.equal(typeof reply, 'object') | ||
|  |       reply.code(204) | ||
|  |       reply.send(undefined) | ||
|  |     }, | ||
|  |     Reply, | ||
|  |     Request, | ||
|  |     preValidation: [], | ||
|  |     preHandler: [], | ||
|  |     onSend: [], | ||
|  |     onError: [] | ||
|  |   } | ||
|  |   buildSchema(context, schemaValidator) | ||
|  |   internals.handler({}, new Reply(res, { context })) | ||
|  | }) | ||
|  | 
 | ||
|  | test('handler function - preValidationCallback with finished response', t => { | ||
|  |   t.plan(0) | ||
|  |   const res = {} | ||
|  |   // Be sure to check only `writableEnded` where is available
 | ||
|  |   if (semver.gte(process.versions.node, '12.9.0')) { | ||
|  |     res.writableEnded = true | ||
|  |   } else { | ||
|  |     res.writable = false | ||
|  |     res.finished = true | ||
|  |   } | ||
|  |   res.end = () => { | ||
|  |     t.fail() | ||
|  |   } | ||
|  |   res.writeHead = () => {} | ||
|  |   const context = { | ||
|  |     handler: (req, reply) => { | ||
|  |       t.fail() | ||
|  |       reply.send(undefined) | ||
|  |     }, | ||
|  |     Reply, | ||
|  |     Request, | ||
|  |     preValidation: null, | ||
|  |     preHandler: [], | ||
|  |     onSend: [], | ||
|  |     onError: [] | ||
|  |   } | ||
|  |   buildSchema(context, schemaValidator) | ||
|  |   internals.handler({}, new Reply(res, { context })) | ||
|  | }) | ||
|  | 
 | ||
|  | test('handler function - preValidationCallback with finished response (< v12.9.0)', t => { | ||
|  |   t.plan(0) | ||
|  |   const res = {} | ||
|  |   // Be sure to check only `writableEnded` where is available
 | ||
|  |   res.writable = false | ||
|  |   res.finished = true | ||
|  | 
 | ||
|  |   res.end = () => { | ||
|  |     t.fail() | ||
|  |   } | ||
|  |   res.writeHead = () => {} | ||
|  |   const context = { | ||
|  |     handler: (req, reply) => { | ||
|  |       t.fail() | ||
|  |       reply.send(undefined) | ||
|  |     }, | ||
|  |     Reply, | ||
|  |     Request, | ||
|  |     preValidation: null, | ||
|  |     preHandler: [], | ||
|  |     onSend: [], | ||
|  |     onError: [] | ||
|  |   } | ||
|  |   buildSchema(context, schemaValidator) | ||
|  |   internals.handler({}, new Reply(res, { context })) | ||
|  | }) | ||
|  | 
 | ||
|  | test('request should be defined in onSend Hook on post request with content type application/json', t => { | ||
|  |   t.plan(8) | ||
|  |   const fastify = require('../..')() | ||
|  | 
 | ||
|  |   fastify.addHook('onSend', (request, reply, payload, done) => { | ||
|  |     t.ok(request) | ||
|  |     t.ok(request.raw) | ||
|  |     t.ok(request.id) | ||
|  |     t.ok(request.params) | ||
|  |     t.ok(request.query) | ||
|  |     done() | ||
|  |   }) | ||
|  |   fastify.post('/', (request, reply) => { | ||
|  |     reply.send(200) | ||
|  |   }) | ||
|  |   fastify.listen(0, err => { | ||
|  |     fastify.server.unref() | ||
|  |     t.error(err) | ||
|  |     sget({ | ||
|  |       method: 'POST', | ||
|  |       url: 'http://localhost:' + fastify.server.address().port, | ||
|  |       headers: { | ||
|  |         'content-type': 'application/json' | ||
|  |       } | ||
|  |     }, (err, response, body) => { | ||
|  |       t.error(err) | ||
|  |       // a 400 error is expected because of no body
 | ||
|  |       t.equal(response.statusCode, 400) | ||
|  |     }) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('request should be defined in onSend Hook on post request with content type application/x-www-form-urlencoded', t => { | ||
|  |   t.plan(7) | ||
|  |   const fastify = require('../..')() | ||
|  | 
 | ||
|  |   fastify.addHook('onSend', (request, reply, payload, done) => { | ||
|  |     t.ok(request) | ||
|  |     t.ok(request.raw) | ||
|  |     t.ok(request.params) | ||
|  |     t.ok(request.query) | ||
|  |     done() | ||
|  |   }) | ||
|  |   fastify.post('/', (request, reply) => { | ||
|  |     reply.send(200) | ||
|  |   }) | ||
|  |   fastify.listen(0, err => { | ||
|  |     fastify.server.unref() | ||
|  |     t.error(err) | ||
|  |     sget({ | ||
|  |       method: 'POST', | ||
|  |       url: 'http://localhost:' + fastify.server.address().port, | ||
|  |       headers: { | ||
|  |         'content-type': 'application/x-www-form-urlencoded' | ||
|  |       } | ||
|  |     }, (err, response, body) => { | ||
|  |       t.error(err) | ||
|  |       // a 415 error is expected because of missing content type parser
 | ||
|  |       t.equal(response.statusCode, 415) | ||
|  |     }) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('request should be defined in onSend Hook on options request with content type application/x-www-form-urlencoded', t => { | ||
|  |   t.plan(7) | ||
|  |   const fastify = require('../..')() | ||
|  | 
 | ||
|  |   fastify.addHook('onSend', (request, reply, payload, done) => { | ||
|  |     t.ok(request) | ||
|  |     t.ok(request.raw) | ||
|  |     t.ok(request.params) | ||
|  |     t.ok(request.query) | ||
|  |     done() | ||
|  |   }) | ||
|  |   fastify.options('/', (request, reply) => { | ||
|  |     reply.send(200) | ||
|  |   }) | ||
|  |   fastify.listen(0, err => { | ||
|  |     fastify.server.unref() | ||
|  |     t.error(err) | ||
|  |     sget({ | ||
|  |       method: 'OPTIONS', | ||
|  |       url: 'http://localhost:' + fastify.server.address().port, | ||
|  |       headers: { | ||
|  |         'content-type': 'application/x-www-form-urlencoded' | ||
|  |       } | ||
|  |     }, (err, response, body) => { | ||
|  |       t.error(err) | ||
|  |       // Body parsing skipped, so no body sent
 | ||
|  |       t.equal(response.statusCode, 200) | ||
|  |     }) | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('request should respond with an error if an unserialized payload is sent inside an async handler', t => { | ||
|  |   t.plan(3) | ||
|  | 
 | ||
|  |   const fastify = require('../..')() | ||
|  | 
 | ||
|  |   fastify.get('/', (request, reply) => { | ||
|  |     reply.type('text/html') | ||
|  |     return Promise.resolve(request.headers) | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.inject({ | ||
|  |     method: 'GET', | ||
|  |     url: '/' | ||
|  |   }, (err, res) => { | ||
|  |     t.error(err) | ||
|  |     t.equal(res.statusCode, 500) | ||
|  |     t.strictSame(JSON.parse(res.payload), { | ||
|  |       error: 'Internal Server Error', | ||
|  |       code: 'FST_ERR_REP_INVALID_PAYLOAD_TYPE', | ||
|  |       message: 'Attempted to send payload of invalid type \'object\'. Expected a string or Buffer.', | ||
|  |       statusCode: 500 | ||
|  |     }) | ||
|  |   }) | ||
|  | }) |