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