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
						
					
					
				'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
 | 
						|
    })
 | 
						|
  })
 | 
						|
})
 |