fatsify核心功能示例测试!!!
This commit is contained in:
38
node_modules/fastify/test/internals/all.test.js
generated
vendored
Normal file
38
node_modules/fastify/test/internals/all.test.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const Fastify = require('../..')
|
||||
|
||||
test('fastify.all should add all the methods to the same url', async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
const requirePayload = [
|
||||
'POST',
|
||||
'PUT',
|
||||
'PATCH'
|
||||
]
|
||||
|
||||
const supportedMethods = fastify.supportedMethods
|
||||
t.plan(supportedMethods.length)
|
||||
|
||||
fastify.all('/', (req, reply) => {
|
||||
reply.send({ method: req.raw.method })
|
||||
})
|
||||
|
||||
await Promise.all(supportedMethods.map(async method => injectRequest(method)))
|
||||
|
||||
async function injectRequest (method) {
|
||||
const options = {
|
||||
url: '/',
|
||||
method
|
||||
}
|
||||
|
||||
if (requirePayload.includes(method)) {
|
||||
options.payload = { hello: 'world' }
|
||||
}
|
||||
|
||||
const res = await fastify.inject(options)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.assert.deepStrictEqual(payload, { method })
|
||||
}
|
||||
})
|
||||
111
node_modules/fastify/test/internals/content-type-parser.test.js
generated
vendored
Normal file
111
node_modules/fastify/test/internals/content-type-parser.test.js
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const proxyquire = require('proxyquire')
|
||||
const { Readable } = require('node:stream')
|
||||
const { kTestInternals, kRouteContext } = require('../../lib/symbols')
|
||||
const Request = require('../../lib/request')
|
||||
const Reply = require('../../lib/reply')
|
||||
|
||||
test('rawBody function', t => {
|
||||
t.plan(2)
|
||||
|
||||
const internals = require('../../lib/contentTypeParser')[kTestInternals]
|
||||
const body = Buffer.from('你好 世界')
|
||||
const parser = {
|
||||
asString: true,
|
||||
asBuffer: false,
|
||||
fn (req, bodyInString, done) {
|
||||
t.assert.strictEqual(bodyInString, body.toString())
|
||||
t.assert.strictEqual(typeof done, 'function')
|
||||
return {
|
||||
then (cb) {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const res = {}
|
||||
res.end = () => { }
|
||||
res.writeHead = () => { }
|
||||
|
||||
res.log = { error: () => { }, info: () => { } }
|
||||
const context = {
|
||||
Reply,
|
||||
Request,
|
||||
preHandler: [],
|
||||
onSend: [],
|
||||
_parserOptions: {
|
||||
limit: 1024
|
||||
}
|
||||
}
|
||||
const rs = new Readable()
|
||||
rs._read = function () { }
|
||||
rs.headers = { 'content-length': body.length }
|
||||
const request = new Request('id', 'params', rs, 'query', 'log', context)
|
||||
const reply = new Reply(res, request)
|
||||
const done = () => { }
|
||||
|
||||
internals.rawBody(
|
||||
request,
|
||||
reply,
|
||||
reply[kRouteContext]._parserOptions,
|
||||
parser,
|
||||
done
|
||||
)
|
||||
rs.emit('data', body.toString())
|
||||
rs.emit('end')
|
||||
})
|
||||
|
||||
test('Should support Webpack and faux modules', t => {
|
||||
t.plan(2)
|
||||
|
||||
const internals = proxyquire('../../lib/contentTypeParser', {
|
||||
'toad-cache': { default: () => { } }
|
||||
})[kTestInternals]
|
||||
|
||||
const body = Buffer.from('你好 世界')
|
||||
const parser = {
|
||||
asString: true,
|
||||
asBuffer: false,
|
||||
fn (req, bodyInString, done) {
|
||||
t.assert.strictEqual(bodyInString, body.toString())
|
||||
t.assert.strictEqual(typeof done, 'function')
|
||||
return {
|
||||
then (cb) {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const res = {}
|
||||
res.end = () => { }
|
||||
res.writeHead = () => { }
|
||||
|
||||
res.log = { error: () => { }, info: () => { } }
|
||||
const context = {
|
||||
Reply,
|
||||
Request,
|
||||
preHandler: [],
|
||||
onSend: [],
|
||||
_parserOptions: {
|
||||
limit: 1024
|
||||
}
|
||||
}
|
||||
const rs = new Readable()
|
||||
rs._read = function () { }
|
||||
rs.headers = { 'content-length': body.length }
|
||||
const request = new Request('id', 'params', rs, 'query', 'log', context)
|
||||
const reply = new Reply(res, request)
|
||||
const done = () => { }
|
||||
|
||||
internals.rawBody(
|
||||
request,
|
||||
reply,
|
||||
reply[kRouteContext]._parserOptions,
|
||||
parser,
|
||||
done
|
||||
)
|
||||
rs.emit('data', body.toString())
|
||||
rs.emit('end')
|
||||
})
|
||||
31
node_modules/fastify/test/internals/context.test.js
generated
vendored
Normal file
31
node_modules/fastify/test/internals/context.test.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const { kRouteContext } = require('../../lib/symbols')
|
||||
const Context = require('../../lib/context')
|
||||
|
||||
const Fastify = require('../..')
|
||||
|
||||
test('context', async context => {
|
||||
context.plan(1)
|
||||
|
||||
await context.test('Should not contain undefined as key prop', async t => {
|
||||
t.plan(4)
|
||||
const app = Fastify()
|
||||
|
||||
app.get('/', (req, reply) => {
|
||||
t.assert.ok(req[kRouteContext] instanceof Context)
|
||||
t.assert.ok(reply[kRouteContext] instanceof Context)
|
||||
t.assert.ok(!('undefined' in reply[kRouteContext]))
|
||||
t.assert.ok(!('undefined' in req[kRouteContext]))
|
||||
|
||||
reply.send('hello world!')
|
||||
})
|
||||
|
||||
try {
|
||||
await app.inject('/')
|
||||
} catch (e) {
|
||||
t.assert.fail(e)
|
||||
}
|
||||
})
|
||||
})
|
||||
156
node_modules/fastify/test/internals/decorator.test.js
generated
vendored
Normal file
156
node_modules/fastify/test/internals/decorator.test.js
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const decorator = require('../../lib/decorate')
|
||||
const {
|
||||
kState
|
||||
} = require('../../lib/symbols')
|
||||
|
||||
test('decorate should add the given method to its instance', t => {
|
||||
t.plan(1)
|
||||
function build () {
|
||||
server.add = decorator.add
|
||||
server[kState] = {
|
||||
listening: false,
|
||||
closing: false,
|
||||
started: false
|
||||
}
|
||||
return server
|
||||
function server () {}
|
||||
}
|
||||
|
||||
const server = build()
|
||||
server.add('test', () => {})
|
||||
t.assert.ok(server.test)
|
||||
})
|
||||
|
||||
test('decorate is chainable', t => {
|
||||
t.plan(3)
|
||||
function build () {
|
||||
server.add = decorator.add
|
||||
server[kState] = {
|
||||
listening: false,
|
||||
closing: false,
|
||||
started: false
|
||||
}
|
||||
return server
|
||||
function server () {}
|
||||
}
|
||||
|
||||
const server = build()
|
||||
server
|
||||
.add('test1', () => {})
|
||||
.add('test2', () => {})
|
||||
.add('test3', () => {})
|
||||
|
||||
t.assert.ok(server.test1)
|
||||
t.assert.ok(server.test2)
|
||||
t.assert.ok(server.test3)
|
||||
})
|
||||
|
||||
test('checkExistence should check if a property is part of the given instance', t => {
|
||||
t.plan(1)
|
||||
const instance = { test: () => {} }
|
||||
t.assert.ok(decorator.exist(instance, 'test'))
|
||||
})
|
||||
|
||||
test('checkExistence should find the instance if not given', t => {
|
||||
t.plan(1)
|
||||
function build () {
|
||||
server.add = decorator.add
|
||||
server.check = decorator.exist
|
||||
server[kState] = {
|
||||
listening: false,
|
||||
closing: false,
|
||||
started: false
|
||||
}
|
||||
return server
|
||||
function server () {}
|
||||
}
|
||||
|
||||
const server = build()
|
||||
server.add('test', () => {})
|
||||
t.assert.ok(server.check('test'))
|
||||
})
|
||||
|
||||
test('checkExistence should check the prototype as well', t => {
|
||||
t.plan(1)
|
||||
function Instance () {}
|
||||
Instance.prototype.test = () => {}
|
||||
|
||||
const instance = new Instance()
|
||||
t.assert.ok(decorator.exist(instance, 'test'))
|
||||
})
|
||||
|
||||
test('checkDependencies should throw if a dependency is not present', t => {
|
||||
t.plan(2)
|
||||
const instance = {}
|
||||
try {
|
||||
decorator.dependencies(instance, 'foo', ['test'])
|
||||
t.assert.fail()
|
||||
} catch (e) {
|
||||
t.assert.strictEqual(e.code, 'FST_ERR_DEC_MISSING_DEPENDENCY')
|
||||
t.assert.strictEqual(e.message, 'The decorator is missing dependency \'test\'.')
|
||||
}
|
||||
})
|
||||
|
||||
test('decorate should internally call checkDependencies', t => {
|
||||
t.plan(2)
|
||||
function build () {
|
||||
server.add = decorator.add
|
||||
server[kState] = {
|
||||
listening: false,
|
||||
closing: false,
|
||||
started: false
|
||||
}
|
||||
return server
|
||||
function server () {}
|
||||
}
|
||||
|
||||
const server = build()
|
||||
|
||||
try {
|
||||
server.add('method', () => {}, ['test'])
|
||||
t.assert.fail()
|
||||
} catch (e) {
|
||||
t.assert.strictEqual(e.code, 'FST_ERR_DEC_MISSING_DEPENDENCY')
|
||||
t.assert.strictEqual(e.message, 'The decorator is missing dependency \'test\'.')
|
||||
}
|
||||
})
|
||||
|
||||
test('decorate should recognize getter/setter objects', t => {
|
||||
t.plan(6)
|
||||
|
||||
const one = {
|
||||
[kState]: {
|
||||
listening: false,
|
||||
closing: false,
|
||||
started: false
|
||||
}
|
||||
}
|
||||
decorator.add.call(one, 'foo', {
|
||||
getter: () => this._a,
|
||||
setter: (val) => {
|
||||
t.assert.ok(true)
|
||||
this._a = val
|
||||
}
|
||||
})
|
||||
t.assert.strictEqual(Object.hasOwn(one, 'foo'), true)
|
||||
t.assert.strictEqual(one.foo, undefined)
|
||||
one.foo = 'a'
|
||||
t.assert.strictEqual(one.foo, 'a')
|
||||
|
||||
// getter only
|
||||
const two = {
|
||||
[kState]: {
|
||||
listening: false,
|
||||
closing: false,
|
||||
started: false
|
||||
}
|
||||
}
|
||||
decorator.add.call(two, 'foo', {
|
||||
getter: () => 'a getter'
|
||||
})
|
||||
t.assert.strictEqual(Object.hasOwn(two, 'foo'), true)
|
||||
t.assert.strictEqual(two.foo, 'a getter')
|
||||
})
|
||||
982
node_modules/fastify/test/internals/errors.test.js
generated
vendored
Normal file
982
node_modules/fastify/test/internals/errors.test.js
generated
vendored
Normal file
@@ -0,0 +1,982 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const errors = require('../../lib/errors')
|
||||
const { readFileSync } = require('node:fs')
|
||||
const { resolve } = require('node:path')
|
||||
|
||||
const expectedErrors = 86
|
||||
|
||||
test(`should expose ${expectedErrors} errors`, t => {
|
||||
t.plan(1)
|
||||
const exportedKeys = Object.keys(errors)
|
||||
let counter = 0
|
||||
for (const key of exportedKeys) {
|
||||
if (errors[key].name === 'FastifyError') {
|
||||
counter++
|
||||
}
|
||||
}
|
||||
t.assert.strictEqual(counter, expectedErrors)
|
||||
})
|
||||
|
||||
test('ensure name and codes of Errors are identical', t => {
|
||||
t.plan(expectedErrors)
|
||||
|
||||
const exportedKeys = Object.keys(errors)
|
||||
for (const key of exportedKeys) {
|
||||
if (errors[key].name === 'FastifyError') {
|
||||
t.assert.strictEqual(key, new errors[key]().code, key)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('FST_ERR_NOT_FOUND', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_NOT_FOUND()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_NOT_FOUND')
|
||||
t.assert.strictEqual(error.message, 'Not Found')
|
||||
t.assert.strictEqual(error.statusCode, 404)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_OPTIONS_NOT_OBJ', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_OPTIONS_NOT_OBJ()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_OPTIONS_NOT_OBJ')
|
||||
t.assert.strictEqual(error.message, 'Options must be an object')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_QSP_NOT_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_QSP_NOT_FN()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_QSP_NOT_FN')
|
||||
t.assert.strictEqual(error.message, "querystringParser option should be a function, instead got '%s'")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN')
|
||||
t.assert.strictEqual(error.message, "schemaController.bucket option should be a function, instead got '%s'")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN')
|
||||
t.assert.strictEqual(error.message, "schemaErrorFormatter option should be a non async function. Instead got '%s'.")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ')
|
||||
t.assert.strictEqual(error.message, "ajv.customOptions option should be an object, instead got '%s'")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR')
|
||||
t.assert.strictEqual(error.message, "ajv.plugins option should be an array, instead got '%s'")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_ALREADY_PRESENT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_ALREADY_PRESENT()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_CTP_ALREADY_PRESENT')
|
||||
t.assert.strictEqual(error.message, "Content type parser '%s' already present.")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_INVALID_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_INVALID_TYPE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_CTP_INVALID_TYPE')
|
||||
t.assert.strictEqual(error.message, 'The content type should be a string or a RegExp')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_EMPTY_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_EMPTY_TYPE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_CTP_EMPTY_TYPE')
|
||||
t.assert.strictEqual(error.message, 'The content type cannot be an empty string')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_INVALID_HANDLER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_INVALID_HANDLER()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_CTP_INVALID_HANDLER')
|
||||
t.assert.strictEqual(error.message, 'The content type handler should be a function')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_INVALID_PARSE_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_INVALID_PARSE_TYPE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_CTP_INVALID_PARSE_TYPE')
|
||||
t.assert.strictEqual(error.message, "The body parser can only parse your data as 'string' or 'buffer', you asked '%s' which is not supported.")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_BODY_TOO_LARGE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_BODY_TOO_LARGE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_CTP_BODY_TOO_LARGE')
|
||||
t.assert.strictEqual(error.message, 'Request body is too large')
|
||||
t.assert.strictEqual(error.statusCode, 413)
|
||||
t.assert.ok(error instanceof RangeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_INVALID_MEDIA_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_INVALID_MEDIA_TYPE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_CTP_INVALID_MEDIA_TYPE')
|
||||
t.assert.strictEqual(error.message, 'Unsupported Media Type: %s')
|
||||
t.assert.strictEqual(error.statusCode, 415)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_INVALID_CONTENT_LENGTH', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_INVALID_CONTENT_LENGTH()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_CTP_INVALID_CONTENT_LENGTH')
|
||||
t.assert.strictEqual(error.message, 'Request body size did not match Content-Length')
|
||||
t.assert.strictEqual(error.statusCode, 400)
|
||||
t.assert.ok(error instanceof RangeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_EMPTY_JSON_BODY', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_EMPTY_JSON_BODY()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_CTP_EMPTY_JSON_BODY')
|
||||
t.assert.strictEqual(error.message, "Body cannot be empty when content-type is set to 'application/json'")
|
||||
t.assert.strictEqual(error.statusCode, 400)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_INVALID_JSON_BODY', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_INVALID_JSON_BODY()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_CTP_INVALID_JSON_BODY')
|
||||
t.assert.strictEqual(error.message, "Body is not valid JSON but content-type is set to 'application/json'")
|
||||
t.assert.strictEqual(error.statusCode, 400)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_INSTANCE_ALREADY_STARTED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_INSTANCE_ALREADY_STARTED()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_CTP_INSTANCE_ALREADY_STARTED')
|
||||
t.assert.strictEqual(error.message, 'Cannot call "%s" when fastify instance is already started!')
|
||||
t.assert.strictEqual(error.statusCode, 400)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_DEC_ALREADY_PRESENT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_DEC_ALREADY_PRESENT()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_DEC_ALREADY_PRESENT')
|
||||
t.assert.strictEqual(error.message, "The decorator '%s' has already been added!")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_DEC_DEPENDENCY_INVALID_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_DEC_DEPENDENCY_INVALID_TYPE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_DEC_DEPENDENCY_INVALID_TYPE')
|
||||
t.assert.strictEqual(error.message, "The dependencies of decorator '%s' must be of type Array.")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_DEC_MISSING_DEPENDENCY', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_DEC_MISSING_DEPENDENCY()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_DEC_MISSING_DEPENDENCY')
|
||||
t.assert.strictEqual(error.message, "The decorator is missing dependency '%s'.")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_DEC_AFTER_START', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_DEC_AFTER_START()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_DEC_AFTER_START')
|
||||
t.assert.strictEqual(error.message, "The decorator '%s' has been added after start!")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_DEC_REFERENCE_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_DEC_REFERENCE_TYPE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_DEC_REFERENCE_TYPE')
|
||||
t.assert.strictEqual(error.message, "The decorator '%s' of type '%s' is a reference type. Use the { getter, setter } interface instead.")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_DEC_UNDECLARED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_DEC_UNDECLARED('myDecorator', 'request')
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_DEC_UNDECLARED')
|
||||
t.assert.strictEqual(error.message, "No decorator 'myDecorator' has been declared on request.")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_HOOK_INVALID_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_HOOK_INVALID_TYPE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_HOOK_INVALID_TYPE')
|
||||
t.assert.strictEqual(error.message, 'The hook name must be a string')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_HOOK_INVALID_HANDLER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_HOOK_INVALID_HANDLER()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_HOOK_INVALID_HANDLER')
|
||||
t.assert.strictEqual(error.message, '%s hook should be a function, instead got %s')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_HOOK_INVALID_ASYNC_HANDLER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_HOOK_INVALID_ASYNC_HANDLER')
|
||||
t.assert.strictEqual(error.message, "Async function has too many arguments. Async hooks should not use the 'done' argument.")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_HOOK_NOT_SUPPORTED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_HOOK_NOT_SUPPORTED()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_HOOK_NOT_SUPPORTED')
|
||||
t.assert.strictEqual(error.message, '%s hook not supported!')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_MISSING_MIDDLEWARE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_MISSING_MIDDLEWARE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_MISSING_MIDDLEWARE')
|
||||
t.assert.strictEqual(error.message, 'You must register a plugin for handling middlewares, visit fastify.dev/docs/latest/Reference/Middleware/ for more info.')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_HOOK_TIMEOUT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_HOOK_TIMEOUT()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_HOOK_TIMEOUT')
|
||||
t.assert.strictEqual(error.message, "A callback for '%s' hook%s timed out. You may have forgotten to call 'done' function or to resolve a Promise")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_LOG_INVALID_DESTINATION', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_LOG_INVALID_DESTINATION()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_LOG_INVALID_DESTINATION')
|
||||
t.assert.strictEqual(error.message, 'Cannot specify both logger.stream and logger.file options')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_LOG_INVALID_LOGGER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_LOG_INVALID_LOGGER()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_LOG_INVALID_LOGGER')
|
||||
t.assert.strictEqual(error.message, "Invalid logger object provided. The logger instance should have these functions(s): '%s'.")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_LOG_INVALID_LOGGER_INSTANCE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_LOG_INVALID_LOGGER_INSTANCE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_LOG_INVALID_LOGGER_INSTANCE')
|
||||
t.assert.strictEqual(error.message, 'loggerInstance only accepts a logger instance.')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_LOG_INVALID_LOGGER_CONFIG', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_LOG_INVALID_LOGGER_CONFIG()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_LOG_INVALID_LOGGER_CONFIG')
|
||||
t.assert.strictEqual(error.message, 'logger options only accepts a configuration object.')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED')
|
||||
t.assert.strictEqual(error.message, 'You cannot provide both logger and loggerInstance. Please provide only one.')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_REP_INVALID_PAYLOAD_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REP_INVALID_PAYLOAD_TYPE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_REP_INVALID_PAYLOAD_TYPE')
|
||||
t.assert.strictEqual(error.message, "Attempted to send payload of invalid type '%s'. Expected a string or Buffer.")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_REP_RESPONSE_BODY_CONSUMED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REP_RESPONSE_BODY_CONSUMED()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_REP_RESPONSE_BODY_CONSUMED')
|
||||
t.assert.strictEqual(error.message, 'Response.body is already consumed.')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_REP_READABLE_STREAM_LOCKED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REP_READABLE_STREAM_LOCKED()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_REP_READABLE_STREAM_LOCKED')
|
||||
t.assert.strictEqual(error.message, 'ReadableStream was locked. You should call releaseLock() method on reader before sending.')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_REP_ALREADY_SENT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REP_ALREADY_SENT('/hello', 'GET')
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_REP_ALREADY_SENT')
|
||||
t.assert.strictEqual(error.message, 'Reply was already sent, did you forget to "return reply" in "/hello" (GET)?')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_REP_SENT_VALUE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REP_SENT_VALUE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_REP_SENT_VALUE')
|
||||
t.assert.strictEqual(error.message, 'The only possible value for reply.sent is true.')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_SEND_INSIDE_ONERR', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SEND_INSIDE_ONERR()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_SEND_INSIDE_ONERR')
|
||||
t.assert.strictEqual(error.message, 'You cannot use `send` inside the `onError` hook')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SEND_UNDEFINED_ERR', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SEND_UNDEFINED_ERR()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_SEND_UNDEFINED_ERR')
|
||||
t.assert.strictEqual(error.message, 'Undefined error has occurred')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_BAD_STATUS_CODE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_BAD_STATUS_CODE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_BAD_STATUS_CODE')
|
||||
t.assert.strictEqual(error.message, 'Called reply with an invalid status code: %s')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_BAD_TRAILER_NAME', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_BAD_TRAILER_NAME()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_BAD_TRAILER_NAME')
|
||||
t.assert.strictEqual(error.message, 'Called reply.trailer with an invalid header name: %s')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_BAD_TRAILER_VALUE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_BAD_TRAILER_VALUE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_BAD_TRAILER_VALUE')
|
||||
t.assert.strictEqual(error.message, "Called reply.trailer('%s', fn) with an invalid type: %s. Expected a function.")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_FAILED_ERROR_SERIALIZATION', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_FAILED_ERROR_SERIALIZATION()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_FAILED_ERROR_SERIALIZATION')
|
||||
t.assert.strictEqual(error.message, 'Failed to serialize an error. Error: %s. Original error: %s')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_MISSING_SERIALIZATION_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_MISSING_SERIALIZATION_FN()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_MISSING_SERIALIZATION_FN')
|
||||
t.assert.strictEqual(error.message, 'Missing serialization function. Key "%s"')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN')
|
||||
t.assert.strictEqual(error.message, 'Missing serialization function. Key "%s:%s"')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_REQ_INVALID_VALIDATION_INVOCATION', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REQ_INVALID_VALIDATION_INVOCATION()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_REQ_INVALID_VALIDATION_INVOCATION')
|
||||
t.assert.strictEqual(error.message, 'Invalid validation invocation. Missing validation function for HTTP part "%s" nor schema provided.')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_MISSING_ID', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_MISSING_ID()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_SCH_MISSING_ID')
|
||||
t.assert.strictEqual(error.message, 'Missing schema $id property')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_ALREADY_PRESENT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_ALREADY_PRESENT()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_SCH_ALREADY_PRESENT')
|
||||
t.assert.strictEqual(error.message, "Schema with id '%s' already declared!")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_CONTENT_MISSING_SCHEMA', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_CONTENT_MISSING_SCHEMA()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_SCH_CONTENT_MISSING_SCHEMA')
|
||||
t.assert.strictEqual(error.message, "Schema is missing for the content type '%s'")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_DUPLICATE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_DUPLICATE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_SCH_DUPLICATE')
|
||||
t.assert.strictEqual(error.message, "Schema with '%s' already present!")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_VALIDATION_BUILD', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_VALIDATION_BUILD()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_SCH_VALIDATION_BUILD')
|
||||
t.assert.strictEqual(error.message, 'Failed building the validation schema for %s: %s, due to error %s')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_SERIALIZATION_BUILD', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_SERIALIZATION_BUILD()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_SCH_SERIALIZATION_BUILD')
|
||||
t.assert.strictEqual(error.message, 'Failed building the serialization schema for %s: %s, due to error %s')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX')
|
||||
t.assert.strictEqual(error.message, 'response schemas should be nested under a valid status code, e.g { 2xx: { type: "object" } }')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_INIT_OPTS_INVALID', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_INIT_OPTS_INVALID()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_INIT_OPTS_INVALID')
|
||||
t.assert.strictEqual(error.message, "Invalid initialization options: '%s'")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE')
|
||||
t.assert.strictEqual(error.message, "Cannot set forceCloseConnections to 'idle' as your HTTP server does not support closeIdleConnections method")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_DUPLICATED_ROUTE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_DUPLICATED_ROUTE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_DUPLICATED_ROUTE')
|
||||
t.assert.strictEqual(error.message, "Method '%s' already declared for route '%s'")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_BAD_URL', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_BAD_URL()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_BAD_URL')
|
||||
t.assert.strictEqual(error.message, "'%s' is not a valid url component")
|
||||
t.assert.strictEqual(error.statusCode, 400)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_ASYNC_CONSTRAINT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ASYNC_CONSTRAINT()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_ASYNC_CONSTRAINT')
|
||||
t.assert.strictEqual(error.message, 'Unexpected error from async constraint')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_INVALID_URL', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_INVALID_URL()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_INVALID_URL')
|
||||
t.assert.strictEqual(error.message, "URL must be a string. Received '%s'")
|
||||
t.assert.strictEqual(error.statusCode, 400)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_OPTIONS_NOT_OBJ', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_OPTIONS_NOT_OBJ()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_ROUTE_OPTIONS_NOT_OBJ')
|
||||
t.assert.strictEqual(error.message, 'Options for "%s:%s" route must be an object')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_DUPLICATED_HANDLER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_DUPLICATED_HANDLER()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_ROUTE_DUPLICATED_HANDLER')
|
||||
t.assert.strictEqual(error.message, 'Duplicate handler for "%s:%s" route is not allowed!')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_HANDLER_NOT_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_HANDLER_NOT_FN()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_ROUTE_HANDLER_NOT_FN')
|
||||
t.assert.strictEqual(error.message, 'Error Handler for %s:%s route, if defined, must be a function')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_MISSING_HANDLER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_MISSING_HANDLER()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_ROUTE_MISSING_HANDLER')
|
||||
t.assert.strictEqual(error.message, 'Missing handler function for "%s:%s" route.')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_METHOD_INVALID', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_METHOD_INVALID()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_ROUTE_METHOD_INVALID')
|
||||
t.assert.strictEqual(error.message, 'Provided method is invalid!')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_METHOD_NOT_SUPPORTED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_METHOD_NOT_SUPPORTED()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_ROUTE_METHOD_NOT_SUPPORTED')
|
||||
t.assert.strictEqual(error.message, '%s method is not supported.')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED')
|
||||
t.assert.strictEqual(error.message, 'Body validation schema for %s:%s route is not supported!')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT')
|
||||
t.assert.strictEqual(error.message, "'bodyLimit' option must be an integer > 0. Got '%s'")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT')
|
||||
t.assert.strictEqual(error.message, "'bodyLimit' option must be an integer > 0. Got '%s'")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_REWRITE_NOT_STR', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_REWRITE_NOT_STR()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_ROUTE_REWRITE_NOT_STR')
|
||||
t.assert.strictEqual(error.message, 'Rewrite url for "%s" needs to be of type "string" but received "%s"')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_REOPENED_CLOSE_SERVER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REOPENED_CLOSE_SERVER()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_REOPENED_CLOSE_SERVER')
|
||||
t.assert.strictEqual(error.message, 'Fastify has already been closed and cannot be reopened')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_REOPENED_SERVER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REOPENED_SERVER()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_REOPENED_SERVER')
|
||||
t.assert.strictEqual(error.message, 'Fastify is already listening')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_INSTANCE_ALREADY_LISTENING', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_INSTANCE_ALREADY_LISTENING()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_INSTANCE_ALREADY_LISTENING')
|
||||
t.assert.strictEqual(error.message, 'Fastify instance is already listening. %s')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_PLUGIN_VERSION_MISMATCH', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_PLUGIN_VERSION_MISMATCH()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_PLUGIN_VERSION_MISMATCH')
|
||||
t.assert.strictEqual(error.message, "fastify-plugin: %s - expected '%s' fastify version, '%s' is installed")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE')
|
||||
t.assert.strictEqual(error.message, "The decorator '%s'%s is not present in %s")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER('easter-egg')
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER')
|
||||
t.assert.strictEqual(error.message, 'The easter-egg plugin being registered mixes async and callback styles. Async plugin should not mix async and callback style.')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_PLUGIN_CALLBACK_NOT_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_PLUGIN_CALLBACK_NOT_FN()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_PLUGIN_CALLBACK_NOT_FN')
|
||||
t.assert.strictEqual(error.message, 'fastify-plugin: %s')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_PLUGIN_NOT_VALID', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_PLUGIN_NOT_VALID()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_PLUGIN_NOT_VALID')
|
||||
t.assert.strictEqual(error.message, 'fastify-plugin: %s')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROOT_PLG_BOOTED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROOT_PLG_BOOTED()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_ROOT_PLG_BOOTED')
|
||||
t.assert.strictEqual(error.message, 'fastify-plugin: %s')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_PARENT_PLUGIN_BOOTED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_PARENT_PLUGIN_BOOTED()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_PARENT_PLUGIN_BOOTED')
|
||||
t.assert.strictEqual(error.message, 'fastify-plugin: %s')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_PLUGIN_TIMEOUT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_PLUGIN_TIMEOUT()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_PLUGIN_TIMEOUT')
|
||||
t.assert.strictEqual(error.message, 'fastify-plugin: %s')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_VALIDATION', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_VALIDATION()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_VALIDATION')
|
||||
t.assert.strictEqual(error.message, '%s')
|
||||
t.assert.strictEqual(error.statusCode, 400)
|
||||
t.assert.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_LISTEN_OPTIONS_INVALID', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_LISTEN_OPTIONS_INVALID()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_LISTEN_OPTIONS_INVALID')
|
||||
t.assert.strictEqual(error.message, "Invalid listen options: '%s'")
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ERROR_HANDLER_NOT_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ERROR_HANDLER_NOT_FN()
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_ERROR_HANDLER_NOT_FN')
|
||||
t.assert.strictEqual(error.message, 'Error Handler must be a function')
|
||||
t.assert.strictEqual(error.statusCode, 500)
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('Ensure that all errors are in Errors.md TOC', t => {
|
||||
t.plan(expectedErrors)
|
||||
|
||||
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')
|
||||
|
||||
const exportedKeys = Object.keys(errors)
|
||||
for (const key of exportedKeys) {
|
||||
if (errors[key].name === 'FastifyError') {
|
||||
t.assert.ok(errorsMd.includes(` - [${key.toUpperCase()}](#${key.toLowerCase()})`), key)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('Ensure that non-existing errors are not in Errors.md TOC', t => {
|
||||
t.plan(expectedErrors)
|
||||
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')
|
||||
|
||||
const matchRE = / {4}- \[([A-Z0-9_]+)\]\(#[a-z0-9_]+\)/g
|
||||
const matches = errorsMd.matchAll(matchRE)
|
||||
const exportedKeys = Object.keys(errors)
|
||||
|
||||
for (const match of matches) {
|
||||
t.assert.ok(exportedKeys.indexOf(match[1]) !== -1, match[1])
|
||||
}
|
||||
})
|
||||
|
||||
test('Ensure that all errors are in Errors.md documented', t => {
|
||||
t.plan(expectedErrors)
|
||||
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')
|
||||
|
||||
const exportedKeys = Object.keys(errors)
|
||||
for (const key of exportedKeys) {
|
||||
if (errors[key].name === 'FastifyError') {
|
||||
t.assert.ok(errorsMd.includes(`<a id="${key.toLowerCase()}">${key.toUpperCase()}</a>`), key)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('Ensure that non-existing errors are not in Errors.md documented', t => {
|
||||
t.plan(expectedErrors)
|
||||
|
||||
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')
|
||||
|
||||
const matchRE = /<a id="[0-9a-zA-Z_]+">([0-9a-zA-Z_]+)<\/a>/g
|
||||
const matches = errorsMd.matchAll(matchRE)
|
||||
const exportedKeys = Object.keys(errors)
|
||||
|
||||
for (const match of matches) {
|
||||
t.assert.ok(exportedKeys.indexOf(match[1]) !== -1, match[1])
|
||||
}
|
||||
})
|
||||
|
||||
test('Ensure that all errors are in errors.d.ts', t => {
|
||||
t.plan(expectedErrors)
|
||||
|
||||
const errorsDts = readFileSync(resolve(__dirname, '../../types/errors.d.ts'), 'utf8')
|
||||
|
||||
const FastifyErrorCodesRE = /export type FastifyErrorCodes = Record<([^>]+),\s*FastifyErrorConstructor>/m
|
||||
|
||||
const [, errorCodeType] = errorsDts.match(FastifyErrorCodesRE)
|
||||
|
||||
const errorCodeRE = /'([A-Z0-9_]+)'/g
|
||||
const matches = errorCodeType.matchAll(errorCodeRE)
|
||||
const errorTypes = [...matches].map(match => match[1])
|
||||
const exportedKeys = Object.keys(errors)
|
||||
|
||||
for (const key of exportedKeys) {
|
||||
if (errors[key].name === 'FastifyError') {
|
||||
t.assert.ok(errorTypes.includes(key), key)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('Ensure that non-existing errors are not in errors.d.ts', t => {
|
||||
t.plan(expectedErrors)
|
||||
|
||||
const errorsDts = readFileSync(resolve(__dirname, '../../types/errors.d.ts'), 'utf8')
|
||||
|
||||
const FastifyErrorCodesRE = /export type FastifyErrorCodes = Record<([^>]+),\s*FastifyErrorConstructor>/m
|
||||
|
||||
const [, errorCodeType] = errorsDts.match(FastifyErrorCodesRE)
|
||||
|
||||
const errorCodeRE = /'([A-Z0-9_]+)'/g
|
||||
const matches = errorCodeType.matchAll(errorCodeRE)
|
||||
const exportedKeys = Object.keys(errors)
|
||||
|
||||
for (const match of matches) {
|
||||
t.assert.ok(exportedKeys.indexOf(match[1]) !== -1, match[1])
|
||||
}
|
||||
})
|
||||
270
node_modules/fastify/test/internals/handle-request.test.js
generated
vendored
Normal file
270
node_modules/fastify/test/internals/handle-request.test.js
generated
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const handleRequest = require('../../lib/handleRequest')
|
||||
const internals = require('../../lib/handleRequest')[Symbol.for('internals')]
|
||||
const Request = require('../../lib/request')
|
||||
const Reply = require('../../lib/reply')
|
||||
const { kRouteContext } = require('../../lib/symbols')
|
||||
const buildSchema = require('../../lib/validation').compileSchemasForValidation
|
||||
|
||||
const Ajv = require('ajv')
|
||||
const ajv = new Ajv({ coerceTypes: true })
|
||||
|
||||
function schemaValidator ({ schema, method, url, httpPart }) {
|
||||
const validateFunction = ajv.compile(schema)
|
||||
const fn = function (body) {
|
||||
const isOk = validateFunction(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.assert.strictEqual(res, undefined)
|
||||
})
|
||||
|
||||
test('handleRequest function - invoke with error', t => {
|
||||
t.plan(1)
|
||||
const request = {}
|
||||
const reply = {}
|
||||
reply.send = (err) => t.assert.strictEqual(err.message, 'Kaboom')
|
||||
handleRequest(new Error('Kaboom'), request, reply)
|
||||
})
|
||||
|
||||
test('handler function - invalid schema', t => {
|
||||
t.plan(1)
|
||||
const res = {}
|
||||
res.log = { error: () => {}, info: () => {} }
|
||||
const context = {
|
||||
config: {
|
||||
method: 'GET',
|
||||
url: '/an-url'
|
||||
},
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'number' }
|
||||
}
|
||||
}
|
||||
},
|
||||
errorHandler: { func: () => { t.assert.ok('errorHandler called') } },
|
||||
handler: () => {},
|
||||
Reply,
|
||||
Request,
|
||||
preValidation: [],
|
||||
preHandler: [],
|
||||
onSend: [],
|
||||
onError: [],
|
||||
attachValidation: false,
|
||||
schemaErrorFormatter: () => new Error()
|
||||
}
|
||||
buildSchema(context, schemaValidator)
|
||||
const request = {
|
||||
body: { hello: 'world' },
|
||||
[kRouteContext]: context
|
||||
}
|
||||
internals.handler(request, new Reply(res, request))
|
||||
})
|
||||
|
||||
test('handler function - reply', t => {
|
||||
t.plan(3)
|
||||
const res = {}
|
||||
res.end = () => {
|
||||
t.assert.strictEqual(res.statusCode, 204)
|
||||
t.assert.ok(true)
|
||||
}
|
||||
res.writeHead = () => {}
|
||||
const context = {
|
||||
handler: (req, reply) => {
|
||||
t.assert.strictEqual(typeof reply, 'object')
|
||||
reply.code(204)
|
||||
reply.send(undefined)
|
||||
},
|
||||
Reply,
|
||||
Request,
|
||||
preValidation: [],
|
||||
preHandler: [],
|
||||
onSend: [],
|
||||
onError: [],
|
||||
config: {
|
||||
url: '',
|
||||
method: ''
|
||||
}
|
||||
}
|
||||
buildSchema(context, schemaValidator)
|
||||
internals.handler({ [kRouteContext]: context }, new Reply(res, { [kRouteContext]: context }))
|
||||
})
|
||||
|
||||
test('handler function - preValidationCallback with finished response', t => {
|
||||
t.plan(0)
|
||||
const res = {}
|
||||
// Be sure to check only `writableEnded` where is available
|
||||
res.writableEnded = true
|
||||
res.end = () => {
|
||||
t.assert.fail()
|
||||
}
|
||||
res.writeHead = () => {}
|
||||
const context = {
|
||||
handler: (req, reply) => {
|
||||
t.assert.fail()
|
||||
reply.send(undefined)
|
||||
},
|
||||
Reply,
|
||||
Request,
|
||||
preValidation: null,
|
||||
preHandler: [],
|
||||
onSend: [],
|
||||
onError: []
|
||||
}
|
||||
buildSchema(context, schemaValidator)
|
||||
internals.handler({ [kRouteContext]: context }, new Reply(res, { [kRouteContext]: context }))
|
||||
})
|
||||
|
||||
test('request should be defined in onSend Hook on post request with content type application/json', async t => {
|
||||
t.plan(6)
|
||||
const fastify = require('../..')()
|
||||
|
||||
t.after(() => {
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.addHook('onSend', (request, reply, payload, done) => {
|
||||
t.assert.ok(request)
|
||||
t.assert.ok(request.raw)
|
||||
t.assert.ok(request.id)
|
||||
t.assert.ok(request.params)
|
||||
t.assert.ok(request.query)
|
||||
done()
|
||||
})
|
||||
fastify.post('/', (request, reply) => {
|
||||
reply.send(200)
|
||||
})
|
||||
|
||||
const fastifyServer = await fastify.listen({ port: 0 })
|
||||
const result = await fetch(fastifyServer, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
t.assert.strictEqual(result.status, 400)
|
||||
})
|
||||
|
||||
test('request should be defined in onSend Hook on post request with content type application/x-www-form-urlencoded', async t => {
|
||||
t.plan(5)
|
||||
const fastify = require('../..')()
|
||||
|
||||
t.after(() => {
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.addHook('onSend', (request, reply, payload, done) => {
|
||||
t.assert.ok(request)
|
||||
t.assert.ok(request.raw)
|
||||
t.assert.ok(request.params)
|
||||
t.assert.ok(request.query)
|
||||
done()
|
||||
})
|
||||
fastify.post('/', (request, reply) => {
|
||||
reply.send(200)
|
||||
})
|
||||
|
||||
const fastifyServer = await fastify.listen({ port: 0 })
|
||||
const result = await fetch(fastifyServer, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
})
|
||||
|
||||
// a 415 error is expected because of missing content type parser
|
||||
t.assert.strictEqual(result.status, 415)
|
||||
})
|
||||
|
||||
test('request should be defined in onSend Hook on options request with content type application/x-www-form-urlencoded', async t => {
|
||||
t.plan(15)
|
||||
const fastify = require('../..')()
|
||||
|
||||
t.after(() => {
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.addHook('onSend', (request, reply, payload, done) => {
|
||||
t.assert.ok(request)
|
||||
t.assert.ok(request.raw)
|
||||
t.assert.ok(request.params)
|
||||
t.assert.ok(request.query)
|
||||
done()
|
||||
})
|
||||
fastify.options('/', (request, reply) => {
|
||||
reply.send(200)
|
||||
})
|
||||
|
||||
// Test 1: OPTIONS with body and content-type header
|
||||
const result1 = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
body: 'first-name=OPTIONS&last-name=METHOD',
|
||||
headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
})
|
||||
|
||||
// Content-Type is not supported
|
||||
t.assert.strictEqual(result1.statusCode, 415)
|
||||
|
||||
// Test 2: OPTIONS with content-type header only (no body)
|
||||
const result2 = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
})
|
||||
|
||||
// Content-Type is not supported
|
||||
t.assert.strictEqual(result2.statusCode, 415)
|
||||
|
||||
// Test 3: OPTIONS with body but no content-type header
|
||||
const result3 = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
body: 'first-name=OPTIONS&last-name=METHOD'
|
||||
})
|
||||
|
||||
// No content-type with payload
|
||||
t.assert.strictEqual(result3.statusCode, 415)
|
||||
})
|
||||
|
||||
test('request should respond with an error if an unserialized payload is sent inside an async handler', async t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = require('../..')()
|
||||
|
||||
fastify.get('/', (request, reply) => {
|
||||
reply.type('text/html')
|
||||
return Promise.resolve(request.headers)
|
||||
})
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
|
||||
t.assert.strictEqual(res.statusCode, 500)
|
||||
t.assert.deepStrictEqual(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
|
||||
})
|
||||
})
|
||||
449
node_modules/fastify/test/internals/hook-runner.test.js
generated
vendored
Normal file
449
node_modules/fastify/test/internals/hook-runner.test.js
generated
vendored
Normal file
@@ -0,0 +1,449 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const { hookRunnerGenerator, onSendHookRunner } = require('../../lib/hooks')
|
||||
|
||||
test('hookRunner - Basic', t => {
|
||||
t.plan(9)
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
hookRunner([fn1, fn2, fn3], 'a', 'b', done)
|
||||
|
||||
function iterator (fn, a, b, done) {
|
||||
return fn(a, b, done)
|
||||
}
|
||||
|
||||
function fn1 (a, b, done) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
done()
|
||||
}
|
||||
|
||||
function fn2 (a, b, done) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
done()
|
||||
}
|
||||
|
||||
function fn3 (a, b, done) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
done()
|
||||
}
|
||||
|
||||
function done (err, a, b) {
|
||||
t.assert.ifError(err)
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
}
|
||||
})
|
||||
|
||||
test('hookRunner - In case of error should skip to done', t => {
|
||||
t.plan(7)
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
hookRunner([fn1, fn2, fn3], 'a', 'b', done)
|
||||
|
||||
function iterator (fn, a, b, done) {
|
||||
return fn(a, b, done)
|
||||
}
|
||||
|
||||
function fn1 (a, b, done) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
done()
|
||||
}
|
||||
|
||||
function fn2 (a, b, done) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
done(new Error('kaboom'))
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.assert.fail('We should not be here')
|
||||
}
|
||||
|
||||
function done (err, a, b) {
|
||||
t.assert.strictEqual(err.message, 'kaboom')
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
}
|
||||
})
|
||||
|
||||
test('hookRunner - Should handle throw', t => {
|
||||
t.plan(7)
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
hookRunner([fn1, fn2, fn3], 'a', 'b', done)
|
||||
|
||||
function iterator (fn, a, b, done) {
|
||||
return fn(a, b, done)
|
||||
}
|
||||
|
||||
function fn1 (a, b, done) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
done()
|
||||
}
|
||||
|
||||
function fn2 (a, b, done) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
throw new Error('kaboom')
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.assert.fail('We should not be here')
|
||||
}
|
||||
|
||||
function done (err, a, b) {
|
||||
t.assert.strictEqual(err.message, 'kaboom')
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
}
|
||||
})
|
||||
|
||||
test('hookRunner - Should handle promises', t => {
|
||||
t.plan(9)
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
hookRunner([fn1, fn2, fn3], 'a', 'b', done)
|
||||
|
||||
function iterator (fn, a, b, done) {
|
||||
return fn(a, b, done)
|
||||
}
|
||||
|
||||
function fn1 (a, b) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function fn2 (a, b) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function fn3 (a, b) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function done (err, a, b) {
|
||||
t.assert.ifError(err)
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
}
|
||||
})
|
||||
|
||||
test('hookRunner - In case of error should skip to done (with promises)', t => {
|
||||
t.plan(7)
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
hookRunner([fn1, fn2, fn3], 'a', 'b', done)
|
||||
|
||||
function iterator (fn, a, b, done) {
|
||||
return fn(a, b, done)
|
||||
}
|
||||
|
||||
function fn1 (a, b) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function fn2 (a, b) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
return Promise.reject(new Error('kaboom'))
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.assert.fail('We should not be here')
|
||||
}
|
||||
|
||||
function done (err, a, b) {
|
||||
t.assert.strictEqual(err.message, 'kaboom')
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
}
|
||||
})
|
||||
|
||||
test('hookRunner - Be able to exit before its natural end', t => {
|
||||
t.plan(4)
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
let shouldStop = false
|
||||
hookRunner([fn1, fn2, fn3], 'a', 'b', done)
|
||||
|
||||
function iterator (fn, a, b, done) {
|
||||
if (shouldStop) {
|
||||
return undefined
|
||||
}
|
||||
return fn(a, b, done)
|
||||
}
|
||||
|
||||
function fn1 (a, b, done) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
done()
|
||||
}
|
||||
|
||||
function fn2 (a, b) {
|
||||
t.assert.strictEqual(a, 'a')
|
||||
t.assert.strictEqual(b, 'b')
|
||||
shouldStop = true
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.assert.fail('this should not be called')
|
||||
}
|
||||
|
||||
function done () {
|
||||
t.assert.fail('this should not be called')
|
||||
}
|
||||
})
|
||||
|
||||
test('hookRunner - Promises that resolve to a value do not change the state', t => {
|
||||
t.plan(5)
|
||||
|
||||
const originalState = { a: 'a', b: 'b' }
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
hookRunner([fn1, fn2, fn3], originalState, 'b', done)
|
||||
|
||||
function iterator (fn, state, b, done) {
|
||||
return fn(state, b, done)
|
||||
}
|
||||
|
||||
function fn1 (state, b, done) {
|
||||
t.assert.strictEqual(state, originalState)
|
||||
return Promise.resolve(null)
|
||||
}
|
||||
|
||||
function fn2 (state, b, done) {
|
||||
t.assert.strictEqual(state, originalState)
|
||||
return Promise.resolve('string')
|
||||
}
|
||||
|
||||
function fn3 (state, b, done) {
|
||||
t.assert.strictEqual(state, originalState)
|
||||
return Promise.resolve({ object: true })
|
||||
}
|
||||
|
||||
function done (err, state, b) {
|
||||
t.assert.ifError(err)
|
||||
t.assert.strictEqual(state, originalState)
|
||||
}
|
||||
})
|
||||
|
||||
test('onSendHookRunner - Basic', t => {
|
||||
t.plan(13)
|
||||
|
||||
const originalRequest = { body: null }
|
||||
const originalReply = { request: originalRequest }
|
||||
const originalPayload = 'payload'
|
||||
|
||||
onSendHookRunner([fn1, fn2, fn3], originalRequest, originalReply, originalPayload, done)
|
||||
|
||||
function fn1 (request, reply, payload, done) {
|
||||
t.assert.deepStrictEqual(request, originalRequest)
|
||||
t.assert.deepStrictEqual(reply, originalReply)
|
||||
t.assert.strictEqual(payload, originalPayload)
|
||||
done()
|
||||
}
|
||||
|
||||
function fn2 (request, reply, payload, done) {
|
||||
t.assert.deepStrictEqual(request, originalRequest)
|
||||
t.assert.deepStrictEqual(reply, originalReply)
|
||||
t.assert.strictEqual(payload, originalPayload)
|
||||
done()
|
||||
}
|
||||
|
||||
function fn3 (request, reply, payload, done) {
|
||||
t.assert.deepStrictEqual(request, originalRequest)
|
||||
t.assert.deepStrictEqual(reply, originalReply)
|
||||
t.assert.strictEqual(payload, originalPayload)
|
||||
done()
|
||||
}
|
||||
|
||||
function done (err, request, reply, payload) {
|
||||
t.assert.ifError(err)
|
||||
t.assert.deepStrictEqual(request, originalRequest)
|
||||
t.assert.deepStrictEqual(reply, originalReply)
|
||||
t.assert.strictEqual(payload, originalPayload)
|
||||
}
|
||||
})
|
||||
|
||||
test('onSendHookRunner - Can change the payload', t => {
|
||||
t.plan(7)
|
||||
|
||||
const originalRequest = { body: null }
|
||||
const originalReply = { request: originalRequest }
|
||||
const v1 = { hello: 'world' }
|
||||
const v2 = { ciao: 'mondo' }
|
||||
const v3 = { winter: 'is coming' }
|
||||
const v4 = { winter: 'has come' }
|
||||
|
||||
onSendHookRunner([fn1, fn2, fn3], originalRequest, originalReply, v1, done)
|
||||
|
||||
function fn1 (request, reply, payload, done) {
|
||||
t.assert.deepStrictEqual(payload, v1)
|
||||
done(null, v2)
|
||||
}
|
||||
|
||||
function fn2 (request, reply, payload, done) {
|
||||
t.assert.deepStrictEqual(payload, v2)
|
||||
done(null, v3)
|
||||
}
|
||||
|
||||
function fn3 (request, reply, payload, done) {
|
||||
t.assert.deepStrictEqual(payload, v3)
|
||||
done(null, v4)
|
||||
}
|
||||
|
||||
function done (err, request, reply, payload) {
|
||||
t.assert.ifError(err)
|
||||
t.assert.deepStrictEqual(request, originalRequest)
|
||||
t.assert.deepStrictEqual(reply, originalReply)
|
||||
t.assert.deepStrictEqual(payload, v4)
|
||||
}
|
||||
})
|
||||
|
||||
test('onSendHookRunner - In case of error should skip to done', t => {
|
||||
t.plan(6)
|
||||
|
||||
const originalRequest = { body: null }
|
||||
const originalReply = { request: originalRequest }
|
||||
const v1 = { hello: 'world' }
|
||||
const v2 = { ciao: 'mondo' }
|
||||
|
||||
onSendHookRunner([fn1, fn2, fn3], originalRequest, originalReply, v1, done)
|
||||
|
||||
function fn1 (request, reply, payload, done) {
|
||||
t.assert.deepStrictEqual(payload, v1)
|
||||
done(null, v2)
|
||||
}
|
||||
|
||||
function fn2 (request, reply, payload, done) {
|
||||
t.assert.deepStrictEqual(payload, v2)
|
||||
done(new Error('kaboom'))
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.assert.fail('We should not be here')
|
||||
}
|
||||
|
||||
function done (err, request, reply, payload) {
|
||||
t.assert.strictEqual(err.message, 'kaboom')
|
||||
t.assert.deepStrictEqual(request, originalRequest)
|
||||
t.assert.deepStrictEqual(reply, originalReply)
|
||||
t.assert.deepStrictEqual(payload, v2)
|
||||
}
|
||||
})
|
||||
|
||||
test('onSendHookRunner - Should handle promises', t => {
|
||||
t.plan(7)
|
||||
|
||||
const originalRequest = { body: null }
|
||||
const originalReply = { request: originalRequest }
|
||||
const v1 = { hello: 'world' }
|
||||
const v2 = { ciao: 'mondo' }
|
||||
const v3 = { winter: 'is coming' }
|
||||
const v4 = { winter: 'has come' }
|
||||
|
||||
onSendHookRunner([fn1, fn2, fn3], originalRequest, originalReply, v1, done)
|
||||
|
||||
function fn1 (request, reply, payload) {
|
||||
t.assert.deepStrictEqual(payload, v1)
|
||||
return Promise.resolve(v2)
|
||||
}
|
||||
|
||||
function fn2 (request, reply, payload) {
|
||||
t.assert.deepStrictEqual(payload, v2)
|
||||
return Promise.resolve(v3)
|
||||
}
|
||||
|
||||
function fn3 (request, reply, payload) {
|
||||
t.assert.deepStrictEqual(payload, v3)
|
||||
return Promise.resolve(v4)
|
||||
}
|
||||
|
||||
function done (err, request, reply, payload) {
|
||||
t.assert.ifError(err)
|
||||
t.assert.deepStrictEqual(request, originalRequest)
|
||||
t.assert.deepStrictEqual(reply, originalReply)
|
||||
t.assert.deepStrictEqual(payload, v4)
|
||||
}
|
||||
})
|
||||
|
||||
test('onSendHookRunner - In case of error should skip to done (with promises)', t => {
|
||||
t.plan(6)
|
||||
|
||||
const originalRequest = { body: null }
|
||||
const originalReply = { request: originalRequest }
|
||||
const v1 = { hello: 'world' }
|
||||
const v2 = { ciao: 'mondo' }
|
||||
|
||||
onSendHookRunner([fn1, fn2, fn3], originalRequest, originalReply, v1, done)
|
||||
|
||||
function fn1 (request, reply, payload) {
|
||||
t.assert.deepStrictEqual(payload, v1)
|
||||
return Promise.resolve(v2)
|
||||
}
|
||||
|
||||
function fn2 (request, reply, payload) {
|
||||
t.assert.deepStrictEqual(payload, v2)
|
||||
return Promise.reject(new Error('kaboom'))
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.assert.fail('We should not be here')
|
||||
}
|
||||
|
||||
function done (err, request, reply, payload) {
|
||||
t.assert.strictEqual(err.message, 'kaboom')
|
||||
t.assert.deepStrictEqual(request, originalRequest)
|
||||
t.assert.deepStrictEqual(reply, originalReply)
|
||||
t.assert.deepStrictEqual(payload, v2)
|
||||
}
|
||||
})
|
||||
|
||||
test('onSendHookRunner - Be able to exit before its natural end', t => {
|
||||
t.plan(2)
|
||||
|
||||
const originalRequest = { body: null }
|
||||
const originalReply = { request: originalRequest }
|
||||
const v1 = { hello: 'world' }
|
||||
const v2 = { ciao: 'mondo' }
|
||||
|
||||
onSendHookRunner([fn1, fn2, fn3], originalRequest, originalReply, v1, done)
|
||||
|
||||
function fn1 (request, reply, payload, done) {
|
||||
t.assert.deepStrictEqual(payload, v1)
|
||||
done(null, v2)
|
||||
}
|
||||
|
||||
function fn2 (request, reply, payload) {
|
||||
t.assert.deepStrictEqual(payload, v2)
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.assert.fail('this should not be called')
|
||||
}
|
||||
|
||||
function done () {
|
||||
t.assert.fail('this should not be called')
|
||||
}
|
||||
})
|
||||
96
node_modules/fastify/test/internals/hooks.test.js
generated
vendored
Normal file
96
node_modules/fastify/test/internals/hooks.test.js
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const { Hooks } = require('../../lib/hooks')
|
||||
const { default: fastify } = require('../../fastify')
|
||||
const noop = () => {}
|
||||
|
||||
test('hooks should have 4 array with the registered hooks', t => {
|
||||
const hooks = new Hooks()
|
||||
t.assert.strictEqual(typeof hooks, 'object')
|
||||
t.assert.ok(Array.isArray(hooks.onRequest))
|
||||
t.assert.ok(Array.isArray(hooks.onSend))
|
||||
t.assert.ok(Array.isArray(hooks.preParsing))
|
||||
t.assert.ok(Array.isArray(hooks.preValidation))
|
||||
t.assert.ok(Array.isArray(hooks.preHandler))
|
||||
t.assert.ok(Array.isArray(hooks.onResponse))
|
||||
t.assert.ok(Array.isArray(hooks.onError))
|
||||
})
|
||||
|
||||
test('hooks.add should add a hook to the given hook', t => {
|
||||
const hooks = new Hooks()
|
||||
hooks.add('onRequest', noop)
|
||||
t.assert.strictEqual(hooks.onRequest.length, 1)
|
||||
t.assert.strictEqual(typeof hooks.onRequest[0], 'function')
|
||||
|
||||
hooks.add('preParsing', noop)
|
||||
t.assert.strictEqual(hooks.preParsing.length, 1)
|
||||
t.assert.strictEqual(typeof hooks.preParsing[0], 'function')
|
||||
|
||||
hooks.add('preValidation', noop)
|
||||
t.assert.strictEqual(hooks.preValidation.length, 1)
|
||||
t.assert.strictEqual(typeof hooks.preValidation[0], 'function')
|
||||
|
||||
hooks.add('preHandler', noop)
|
||||
t.assert.strictEqual(hooks.preHandler.length, 1)
|
||||
t.assert.strictEqual(typeof hooks.preHandler[0], 'function')
|
||||
|
||||
hooks.add('onResponse', noop)
|
||||
t.assert.strictEqual(hooks.onResponse.length, 1)
|
||||
t.assert.strictEqual(typeof hooks.onResponse[0], 'function')
|
||||
|
||||
hooks.add('onSend', noop)
|
||||
t.assert.strictEqual(hooks.onSend.length, 1)
|
||||
t.assert.strictEqual(typeof hooks.onSend[0], 'function')
|
||||
|
||||
hooks.add('onError', noop)
|
||||
t.assert.strictEqual(hooks.onError.length, 1)
|
||||
t.assert.strictEqual(typeof hooks.onError[0], 'function')
|
||||
})
|
||||
|
||||
test('hooks should throw on unexisting handler', t => {
|
||||
t.plan(1)
|
||||
const hooks = new Hooks()
|
||||
try {
|
||||
hooks.add('onUnexistingHook', noop)
|
||||
t.assert.fail()
|
||||
} catch (e) {
|
||||
t.assert.ok(true)
|
||||
}
|
||||
})
|
||||
|
||||
test('should throw on wrong parameters', t => {
|
||||
const hooks = new Hooks()
|
||||
t.plan(4)
|
||||
try {
|
||||
hooks.add(null, () => {})
|
||||
t.assert.fail()
|
||||
} catch (e) {
|
||||
t.assert.strictEqual(e.code, 'FST_ERR_HOOK_INVALID_TYPE')
|
||||
t.assert.strictEqual(e.message, 'The hook name must be a string')
|
||||
}
|
||||
|
||||
try {
|
||||
hooks.add('onSend', null)
|
||||
t.assert.fail()
|
||||
} catch (e) {
|
||||
t.assert.strictEqual(e.code, 'FST_ERR_HOOK_INVALID_HANDLER')
|
||||
t.assert.strictEqual(e.message, 'onSend hook should be a function, instead got [object Null]')
|
||||
}
|
||||
})
|
||||
|
||||
test('Integration test: internal function _addHook should be turned into app.ready() rejection', async (t) => {
|
||||
const app = fastify()
|
||||
|
||||
app.register(async function () {
|
||||
app.addHook('notRealHook', async () => {})
|
||||
})
|
||||
|
||||
try {
|
||||
await app.ready()
|
||||
t.assert.fail('Expected ready() to throw')
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(err.code, 'FST_ERR_HOOK_NOT_SUPPORTED')
|
||||
t.assert.match(err.message, /hook not supported/i)
|
||||
}
|
||||
})
|
||||
381
node_modules/fastify/test/internals/initial-config.test.js
generated
vendored
Normal file
381
node_modules/fastify/test/internals/initial-config.test.js
generated
vendored
Normal file
@@ -0,0 +1,381 @@
|
||||
'use strict'
|
||||
|
||||
const { test, before } = require('node:test')
|
||||
const Fastify = require('../..')
|
||||
const helper = require('../helper')
|
||||
const http = require('node:http')
|
||||
const pino = require('pino')
|
||||
const split = require('split2')
|
||||
const deepClone = require('rfdc')({ circles: true, proto: false })
|
||||
const { deepFreezeObject } = require('../../lib/initialConfigValidation').utils
|
||||
|
||||
const { buildCertificate } = require('../build-certificate')
|
||||
|
||||
process.removeAllListeners('warning')
|
||||
|
||||
let localhost
|
||||
let localhostForURL
|
||||
|
||||
before(async function () {
|
||||
await buildCertificate();
|
||||
[localhost, localhostForURL] = await helper.getLoopbackHost()
|
||||
})
|
||||
|
||||
test('Fastify.initialConfig is an object', t => {
|
||||
t.plan(1)
|
||||
t.assert.ok(typeof Fastify().initialConfig === 'object')
|
||||
})
|
||||
|
||||
test('without options passed to Fastify, initialConfig should expose default values', t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastifyDefaultOptions = {
|
||||
connectionTimeout: 0,
|
||||
keepAliveTimeout: 72000,
|
||||
maxRequestsPerSocket: 0,
|
||||
requestTimeout: 0,
|
||||
bodyLimit: 1024 * 1024,
|
||||
caseSensitive: true,
|
||||
allowUnsafeRegex: false,
|
||||
disableRequestLogging: false,
|
||||
ignoreTrailingSlash: false,
|
||||
ignoreDuplicateSlashes: false,
|
||||
maxParamLength: 100,
|
||||
onProtoPoisoning: 'error',
|
||||
onConstructorPoisoning: 'error',
|
||||
pluginTimeout: 10000,
|
||||
requestIdHeader: false,
|
||||
requestIdLogLabel: 'reqId',
|
||||
http2SessionTimeout: 72000,
|
||||
exposeHeadRoutes: true,
|
||||
useSemicolonDelimiter: false
|
||||
}
|
||||
|
||||
t.assert.deepStrictEqual(Fastify().initialConfig, fastifyDefaultOptions)
|
||||
})
|
||||
|
||||
test('Fastify.initialConfig should expose all options', t => {
|
||||
t.plan(22)
|
||||
|
||||
const serverFactory = (handler, opts) => {
|
||||
const server = http.createServer((req, res) => {
|
||||
handler(req, res)
|
||||
})
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
const versionStrategy = {
|
||||
name: 'version',
|
||||
storage: function () {
|
||||
const versions = {}
|
||||
return {
|
||||
get: (version) => { return versions[version] || null },
|
||||
set: (version, store) => { versions[version] = store }
|
||||
}
|
||||
},
|
||||
deriveConstraint: (req, ctx) => {
|
||||
return req.headers.accept
|
||||
},
|
||||
validate () { return true }
|
||||
}
|
||||
|
||||
let reqId = 0
|
||||
const options = {
|
||||
http2: true,
|
||||
https: {
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
},
|
||||
ignoreTrailingSlash: true,
|
||||
ignoreDuplicateSlashes: true,
|
||||
maxParamLength: 200,
|
||||
connectionTimeout: 0,
|
||||
keepAliveTimeout: 72000,
|
||||
bodyLimit: 1049600,
|
||||
onProtoPoisoning: 'remove',
|
||||
serverFactory,
|
||||
caseSensitive: true,
|
||||
allowUnsafeRegex: false,
|
||||
requestIdHeader: 'request-id-alt',
|
||||
pluginTimeout: 20000,
|
||||
useSemicolonDelimiter: false,
|
||||
querystringParser: str => str,
|
||||
genReqId: function (req) {
|
||||
return reqId++
|
||||
},
|
||||
loggerInstance: pino({ level: 'info' }),
|
||||
constraints: {
|
||||
version: versionStrategy
|
||||
},
|
||||
trustProxy: function myTrustFn (address, hop) {
|
||||
return address === '1.2.3.4' || hop === 1
|
||||
}
|
||||
}
|
||||
|
||||
const fastify = Fastify(options)
|
||||
t.assert.strictEqual(fastify.initialConfig.http2, true)
|
||||
t.assert.strictEqual(fastify.initialConfig.https, true, 'for security reason the key cert is hidden')
|
||||
t.assert.strictEqual(fastify.initialConfig.ignoreTrailingSlash, true)
|
||||
t.assert.strictEqual(fastify.initialConfig.ignoreDuplicateSlashes, true)
|
||||
t.assert.strictEqual(fastify.initialConfig.maxParamLength, 200)
|
||||
t.assert.strictEqual(fastify.initialConfig.connectionTimeout, 0)
|
||||
t.assert.strictEqual(fastify.initialConfig.keepAliveTimeout, 72000)
|
||||
t.assert.strictEqual(fastify.initialConfig.bodyLimit, 1049600)
|
||||
t.assert.strictEqual(fastify.initialConfig.onProtoPoisoning, 'remove')
|
||||
t.assert.strictEqual(fastify.initialConfig.caseSensitive, true)
|
||||
t.assert.strictEqual(fastify.initialConfig.useSemicolonDelimiter, false)
|
||||
t.assert.strictEqual(fastify.initialConfig.allowUnsafeRegex, false)
|
||||
t.assert.strictEqual(fastify.initialConfig.requestIdHeader, 'request-id-alt')
|
||||
t.assert.strictEqual(fastify.initialConfig.pluginTimeout, 20000)
|
||||
t.assert.ok(fastify.initialConfig.constraints.version)
|
||||
|
||||
// obfuscated options:
|
||||
t.assert.strictEqual(fastify.initialConfig.serverFactory, undefined)
|
||||
t.assert.strictEqual(fastify.initialConfig.trustProxy, undefined)
|
||||
t.assert.strictEqual(fastify.initialConfig.genReqId, undefined)
|
||||
t.assert.strictEqual(fastify.initialConfig.childLoggerFactory, undefined)
|
||||
t.assert.strictEqual(fastify.initialConfig.querystringParser, undefined)
|
||||
t.assert.strictEqual(fastify.initialConfig.logger, undefined)
|
||||
t.assert.strictEqual(fastify.initialConfig.trustProxy, undefined)
|
||||
})
|
||||
|
||||
test('Should throw if you try to modify Fastify.initialConfig', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify({ ignoreTrailingSlash: true })
|
||||
try {
|
||||
fastify.initialConfig.ignoreTrailingSlash = false
|
||||
t.assert.fail()
|
||||
} catch (error) {
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
t.assert.strictEqual(error.message, "Cannot assign to read only property 'ignoreTrailingSlash' of object '#<Object>'")
|
||||
t.assert.ok(error.stack)
|
||||
t.assert.ok(true)
|
||||
}
|
||||
})
|
||||
|
||||
test('We must avoid shallow freezing and ensure that the whole object is freezed', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify({
|
||||
https: {
|
||||
allowHTTP1: true,
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
fastify.initialConfig.https.allowHTTP1 = false
|
||||
t.assert.fail()
|
||||
} catch (error) {
|
||||
t.assert.ok(error instanceof TypeError)
|
||||
t.assert.strictEqual(error.message, "Cannot assign to read only property 'allowHTTP1' of object '#<Object>'")
|
||||
t.assert.ok(error.stack)
|
||||
t.assert.deepStrictEqual(fastify.initialConfig.https, {
|
||||
allowHTTP1: true
|
||||
}, 'key cert removed')
|
||||
}
|
||||
})
|
||||
|
||||
test('https value check', t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify({})
|
||||
t.assert.ok(!fastify.initialConfig.https)
|
||||
})
|
||||
|
||||
test('Return an error if options do not match the validation schema', t => {
|
||||
t.plan(6)
|
||||
|
||||
try {
|
||||
Fastify({ ignoreTrailingSlash: 'string instead of boolean' })
|
||||
|
||||
t.assert.fail()
|
||||
} catch (error) {
|
||||
t.assert.ok(error instanceof Error)
|
||||
t.assert.strictEqual(error.name, 'FastifyError')
|
||||
t.assert.strictEqual(error.message, 'Invalid initialization options: \'["must be boolean"]\'')
|
||||
t.assert.strictEqual(error.code, 'FST_ERR_INIT_OPTS_INVALID')
|
||||
t.assert.ok(error.stack)
|
||||
t.assert.ok(true)
|
||||
}
|
||||
})
|
||||
|
||||
test('Original options must not be frozen', t => {
|
||||
t.plan(4)
|
||||
|
||||
const originalOptions = {
|
||||
https: {
|
||||
allowHTTP1: true,
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
}
|
||||
}
|
||||
|
||||
const fastify = Fastify(originalOptions)
|
||||
|
||||
t.assert.strictEqual(Object.isFrozen(originalOptions), false)
|
||||
t.assert.strictEqual(Object.isFrozen(originalOptions.https), false)
|
||||
t.assert.strictEqual(Object.isFrozen(fastify.initialConfig), true)
|
||||
t.assert.strictEqual(Object.isFrozen(fastify.initialConfig.https), true)
|
||||
})
|
||||
|
||||
test('Original options must not be altered (test deep cloning)', t => {
|
||||
t.plan(3)
|
||||
|
||||
const originalOptions = {
|
||||
https: {
|
||||
allowHTTP1: true,
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
}
|
||||
}
|
||||
|
||||
const originalOptionsClone = deepClone(originalOptions)
|
||||
|
||||
const fastify = Fastify(originalOptions)
|
||||
|
||||
// initialConfig has been triggered
|
||||
t.assert.strictEqual(Object.isFrozen(fastify.initialConfig), true)
|
||||
|
||||
// originalOptions must not have been altered
|
||||
t.assert.deepStrictEqual(originalOptions.https.key, originalOptionsClone.https.key)
|
||||
t.assert.deepStrictEqual(originalOptions.https.cert, originalOptionsClone.https.cert)
|
||||
})
|
||||
|
||||
test('Should not have issues when passing stream options to Pino.js', (t, done) => {
|
||||
t.plan(17)
|
||||
|
||||
const stream = split(JSON.parse)
|
||||
|
||||
const originalOptions = {
|
||||
ignoreTrailingSlash: true,
|
||||
logger: {
|
||||
level: 'trace',
|
||||
stream
|
||||
}
|
||||
}
|
||||
|
||||
let fastify
|
||||
|
||||
try {
|
||||
fastify = Fastify(originalOptions)
|
||||
fastify.setChildLoggerFactory(function (logger, bindings, opts) {
|
||||
bindings.someBinding = 'value'
|
||||
return logger.child(bindings, opts)
|
||||
})
|
||||
|
||||
t.assert.ok(typeof fastify === 'object')
|
||||
t.assert.deepStrictEqual(fastify.initialConfig, {
|
||||
connectionTimeout: 0,
|
||||
keepAliveTimeout: 72000,
|
||||
maxRequestsPerSocket: 0,
|
||||
requestTimeout: 0,
|
||||
bodyLimit: 1024 * 1024,
|
||||
caseSensitive: true,
|
||||
allowUnsafeRegex: false,
|
||||
disableRequestLogging: false,
|
||||
ignoreTrailingSlash: true,
|
||||
ignoreDuplicateSlashes: false,
|
||||
maxParamLength: 100,
|
||||
onProtoPoisoning: 'error',
|
||||
onConstructorPoisoning: 'error',
|
||||
pluginTimeout: 10000,
|
||||
requestIdHeader: false,
|
||||
requestIdLogLabel: 'reqId',
|
||||
http2SessionTimeout: 72000,
|
||||
exposeHeadRoutes: true,
|
||||
useSemicolonDelimiter: false
|
||||
})
|
||||
} catch (error) {
|
||||
t.assert.fail()
|
||||
}
|
||||
|
||||
fastify.get('/', function (req, reply) {
|
||||
t.assert.ok(req.log)
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
stream.once('data', listenAtLogLine => {
|
||||
t.assert.ok(listenAtLogLine, 'listen at log message is ok')
|
||||
|
||||
stream.once('data', line => {
|
||||
const id = line.reqId
|
||||
t.assert.ok(line.reqId, 'reqId is defined')
|
||||
t.assert.strictEqual(line.someBinding, 'value', 'child logger binding is set')
|
||||
t.assert.ok(line.req, 'req is defined')
|
||||
t.assert.strictEqual(line.msg, 'incoming request', 'message is set')
|
||||
t.assert.strictEqual(line.req.method, 'GET', 'method is get')
|
||||
|
||||
stream.once('data', line => {
|
||||
t.assert.strictEqual(line.reqId, id)
|
||||
t.assert.ok(line.reqId, 'reqId is defined')
|
||||
t.assert.strictEqual(line.someBinding, 'value', 'child logger binding is set')
|
||||
t.assert.ok(line.res, 'res is defined')
|
||||
t.assert.strictEqual(line.msg, 'request completed', 'message is set')
|
||||
t.assert.strictEqual(line.res.statusCode, 200, 'statusCode is 200')
|
||||
t.assert.ok(line.responseTime, 'responseTime is defined')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0, host: localhost }, err => {
|
||||
t.assert.ifError(err)
|
||||
t.after(() => { fastify.close() })
|
||||
|
||||
http.get(`http://${localhostForURL}:${fastify.server.address().port}`, () => {
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('deepFreezeObject() should not throw on TypedArray', t => {
|
||||
t.plan(5)
|
||||
|
||||
const object = {
|
||||
buffer: Buffer.from(global.context.key),
|
||||
dataView: new DataView(new ArrayBuffer(16)),
|
||||
float: 1.1,
|
||||
integer: 1,
|
||||
object: {
|
||||
nested: { string: 'string' }
|
||||
},
|
||||
stream: split(JSON.parse),
|
||||
string: 'string'
|
||||
}
|
||||
|
||||
try {
|
||||
const frozenObject = deepFreezeObject(object)
|
||||
|
||||
// Buffers should not be frozen, as they are Uint8Array inherited instances
|
||||
t.assert.strictEqual(Object.isFrozen(frozenObject.buffer), false)
|
||||
|
||||
t.assert.strictEqual(Object.isFrozen(frozenObject), true)
|
||||
t.assert.strictEqual(Object.isFrozen(frozenObject.object), true)
|
||||
t.assert.strictEqual(Object.isFrozen(frozenObject.object.nested), true)
|
||||
|
||||
t.assert.ok(true)
|
||||
} catch (error) {
|
||||
t.assert.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('pluginTimeout should be parsed correctly', t => {
|
||||
const withDisabledTimeout = Fastify({ pluginTimeout: '0' })
|
||||
t.assert.strictEqual(withDisabledTimeout.initialConfig.pluginTimeout, 0)
|
||||
const withInvalidTimeout = Fastify({ pluginTimeout: undefined })
|
||||
t.assert.strictEqual(withInvalidTimeout.initialConfig.pluginTimeout, 10000)
|
||||
})
|
||||
|
||||
test('Should not mutate the options object outside Fastify', async t => {
|
||||
const options = Object.freeze({})
|
||||
|
||||
try {
|
||||
Fastify(options)
|
||||
t.assert.ok(true)
|
||||
} catch (error) {
|
||||
t.assert.fail(error.message)
|
||||
}
|
||||
})
|
||||
163
node_modules/fastify/test/internals/logger.test.js
generated
vendored
Normal file
163
node_modules/fastify/test/internals/logger.test.js
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const Fastify = require('../..')
|
||||
const loggerUtils = require('../../lib/logger-factory')
|
||||
const { serializers } = require('../../lib/logger-pino')
|
||||
|
||||
test('time resolution', t => {
|
||||
t.plan(2)
|
||||
t.assert.strictEqual(typeof loggerUtils.now, 'function')
|
||||
t.assert.strictEqual(typeof loggerUtils.now(), 'number')
|
||||
})
|
||||
|
||||
test('The logger should add a unique id for every request', (t, done) => {
|
||||
const ids = []
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.assert.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.assert.ifError(err)
|
||||
const queue = new Queue()
|
||||
for (let i = 0; i < 10; i++) {
|
||||
queue.add(checkId)
|
||||
}
|
||||
queue.add(() => {
|
||||
fastify.close()
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
function checkId (done) {
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port
|
||||
}, (err, res) => {
|
||||
t.assert.ifError(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.assert.ok(ids.indexOf(payload.id) === -1, 'the id should not be duplicated')
|
||||
ids.push(payload.id)
|
||||
done()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('The logger should not reuse request id header for req.id', (t, done) => {
|
||||
const fastify = Fastify()
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.assert.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.assert.ifError(err)
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
headers: {
|
||||
'Request-Id': 'request-id-1'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.assert.ifError(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.assert.ok(payload.id !== 'request-id-1', 'the request id from the header should not be returned with default configuration')
|
||||
t.assert.ok(payload.id === 'req-1') // first request id when using the default configuration
|
||||
fastify.close()
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('The logger should reuse request id header for req.id if requestIdHeader is set', (t, done) => {
|
||||
const fastify = Fastify({
|
||||
requestIdHeader: 'request-id'
|
||||
})
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.assert.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.assert.ifError(err)
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
headers: {
|
||||
'Request-Id': 'request-id-1'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.assert.ifError(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.assert.ok(payload.id === 'request-id-1', 'the request id from the header should be returned')
|
||||
fastify.close()
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function Queue () {
|
||||
this.q = []
|
||||
this.running = false
|
||||
}
|
||||
|
||||
Queue.prototype.add = function add (job) {
|
||||
this.q.push(job)
|
||||
if (!this.running) this.run()
|
||||
}
|
||||
|
||||
Queue.prototype.run = function run () {
|
||||
this.running = true
|
||||
const job = this.q.shift()
|
||||
job(() => {
|
||||
if (this.q.length) {
|
||||
this.run()
|
||||
} else {
|
||||
this.running = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
test('The logger should error if both stream and file destination are given', t => {
|
||||
t.plan(2)
|
||||
|
||||
const stream = require('node:stream').Writable
|
||||
|
||||
try {
|
||||
Fastify({
|
||||
logger: {
|
||||
level: 'info',
|
||||
stream,
|
||||
file: '/test'
|
||||
}
|
||||
})
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(err.code, 'FST_ERR_LOG_INVALID_DESTINATION')
|
||||
t.assert.strictEqual(err.message, 'Cannot specify both logger.stream and logger.file options')
|
||||
}
|
||||
})
|
||||
|
||||
test('The serializer prevent fails if the request socket is undefined', t => {
|
||||
t.plan(1)
|
||||
|
||||
const serialized = serializers.req({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: undefined,
|
||||
headers: {}
|
||||
})
|
||||
|
||||
t.assert.deepStrictEqual(serialized, {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
version: undefined,
|
||||
host: undefined,
|
||||
remoteAddress: undefined,
|
||||
remotePort: undefined
|
||||
})
|
||||
})
|
||||
170
node_modules/fastify/test/internals/plugin.test.js
generated
vendored
Normal file
170
node_modules/fastify/test/internals/plugin.test.js
generated
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
|
||||
const pluginUtilsPublic = require('../../lib/pluginUtils.js')
|
||||
const symbols = require('../../lib/symbols.js')
|
||||
const pluginUtils = require('../../lib/pluginUtils')[symbols.kTestInternals]
|
||||
|
||||
test("shouldSkipOverride should check the 'skip-override' symbol", t => {
|
||||
t.plan(2)
|
||||
|
||||
yes[Symbol.for('skip-override')] = true
|
||||
|
||||
t.assert.ok(pluginUtils.shouldSkipOverride(yes))
|
||||
t.assert.ok(!pluginUtils.shouldSkipOverride(no))
|
||||
|
||||
function yes () {}
|
||||
function no () {}
|
||||
})
|
||||
|
||||
test('getPluginName should return plugin name if the file is cached', t => {
|
||||
t.plan(1)
|
||||
const expectedPluginName = 'example'
|
||||
const fn = () => console.log('is just an example')
|
||||
require.cache[expectedPluginName] = { exports: fn }
|
||||
const pluginName = pluginUtilsPublic.getPluginName(fn)
|
||||
|
||||
t.assert.strictEqual(pluginName, expectedPluginName)
|
||||
})
|
||||
|
||||
test('getPluginName should not throw when require.cache is undefined', t => {
|
||||
t.plan(1)
|
||||
function example () {
|
||||
console.log('is just an example')
|
||||
}
|
||||
const cache = require.cache
|
||||
require.cache = undefined
|
||||
t.after(() => {
|
||||
require.cache = cache
|
||||
})
|
||||
const pluginName = pluginUtilsPublic.getPluginName(example)
|
||||
|
||||
t.assert.strictEqual(pluginName, 'example')
|
||||
})
|
||||
|
||||
test("getMeta should return the object stored with the 'plugin-meta' symbol", t => {
|
||||
t.plan(1)
|
||||
|
||||
const meta = { hello: 'world' }
|
||||
fn[Symbol.for('plugin-meta')] = meta
|
||||
|
||||
t.assert.deepStrictEqual(meta, pluginUtils.getMeta(fn))
|
||||
|
||||
function fn () {}
|
||||
})
|
||||
|
||||
test('checkDecorators should check if the given decorator is present in the instance', t => {
|
||||
t.plan(1)
|
||||
|
||||
fn[Symbol.for('plugin-meta')] = {
|
||||
decorators: {
|
||||
fastify: ['plugin'],
|
||||
reply: ['plugin'],
|
||||
request: ['plugin']
|
||||
}
|
||||
}
|
||||
|
||||
function context () {}
|
||||
context.plugin = true
|
||||
context[symbols.kReply] = { prototype: { plugin: true }, props: [] }
|
||||
context[symbols.kRequest] = { prototype: { plugin: true }, props: [] }
|
||||
|
||||
try {
|
||||
pluginUtils.checkDecorators.call(context, fn)
|
||||
t.assert.ok('Everything ok')
|
||||
} catch (err) {
|
||||
t.assert.fail(err)
|
||||
}
|
||||
|
||||
function fn () {}
|
||||
})
|
||||
|
||||
test('checkDecorators should check if the given decorator is present in the instance (errored)', t => {
|
||||
t.plan(1)
|
||||
|
||||
fn[Symbol.for('plugin-meta')] = {
|
||||
decorators: {
|
||||
fastify: ['plugin'],
|
||||
reply: ['plugin'],
|
||||
request: ['plugin']
|
||||
}
|
||||
}
|
||||
|
||||
function context () {}
|
||||
context.plugin = true
|
||||
context[symbols.kReply] = { prototype: { plugin: true }, props: [] }
|
||||
context[symbols.kRequest] = { prototype: {}, props: [] }
|
||||
|
||||
try {
|
||||
pluginUtils.checkDecorators.call(context, fn)
|
||||
t.assert.fail('should throw')
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(err.message, "The decorator 'plugin' is not present in Request")
|
||||
}
|
||||
|
||||
function fn () {}
|
||||
})
|
||||
|
||||
test('checkDecorators should accept optional decorators', t => {
|
||||
t.plan(1)
|
||||
|
||||
fn[Symbol.for('plugin-meta')] = {
|
||||
decorators: { }
|
||||
}
|
||||
|
||||
function context () {}
|
||||
context.plugin = true
|
||||
context[symbols.kReply] = { prototype: { plugin: true } }
|
||||
context[symbols.kRequest] = { prototype: { plugin: true } }
|
||||
|
||||
try {
|
||||
pluginUtils.checkDecorators.call(context, fn)
|
||||
t.assert.ok('Everything ok')
|
||||
} catch (err) {
|
||||
t.assert.fail(err)
|
||||
}
|
||||
|
||||
function fn () {}
|
||||
})
|
||||
|
||||
test('checkDependencies should check if the given dependency is present in the instance', t => {
|
||||
t.plan(1)
|
||||
|
||||
fn[Symbol.for('plugin-meta')] = {
|
||||
dependencies: ['plugin']
|
||||
}
|
||||
|
||||
function context () {}
|
||||
context[pluginUtilsPublic.kRegisteredPlugins] = ['plugin']
|
||||
|
||||
try {
|
||||
pluginUtils.checkDependencies.call(context, fn)
|
||||
t.assert.ok('Everything ok')
|
||||
} catch (err) {
|
||||
t.assert.fail(err)
|
||||
}
|
||||
|
||||
function fn () {}
|
||||
})
|
||||
|
||||
test('checkDependencies should check if the given dependency is present in the instance (errored)', t => {
|
||||
t.plan(1)
|
||||
|
||||
fn[Symbol.for('plugin-meta')] = {
|
||||
name: 'test-plugin',
|
||||
dependencies: ['plugin']
|
||||
}
|
||||
|
||||
function context () {}
|
||||
context[pluginUtilsPublic.kRegisteredPlugins] = []
|
||||
|
||||
try {
|
||||
pluginUtils.checkDependencies.call(context, fn)
|
||||
t.assert.fail('should throw')
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(err.message, "The dependency 'plugin' of plugin 'test-plugin' is not registered")
|
||||
}
|
||||
|
||||
function fn () {}
|
||||
})
|
||||
63
node_modules/fastify/test/internals/promise.test.js
generated
vendored
Normal file
63
node_modules/fastify/test/internals/promise.test.js
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
|
||||
const { kTestInternals } = require('../../lib/symbols')
|
||||
const PonyPromise = require('../../lib/promise')
|
||||
|
||||
test('withResolvers', async (t) => {
|
||||
t.plan(3)
|
||||
await t.test('resolve', async (t) => {
|
||||
t.plan(1)
|
||||
const { promise, resolve } = PonyPromise.withResolvers()
|
||||
resolve(true)
|
||||
t.assert.ok(await promise)
|
||||
})
|
||||
await t.test('reject', async (t) => {
|
||||
t.plan(1)
|
||||
const { promise, reject } = PonyPromise.withResolvers()
|
||||
await t.assert.rejects(async () => {
|
||||
reject(Error('reject'))
|
||||
return promise
|
||||
}, {
|
||||
name: 'Error',
|
||||
message: 'reject'
|
||||
})
|
||||
})
|
||||
await t.test('thenable', async (t) => {
|
||||
t.plan(1)
|
||||
const { promise, resolve } = PonyPromise.withResolvers()
|
||||
resolve(true)
|
||||
promise.then((value) => {
|
||||
t.assert.ok(value)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('withResolvers - ponyfill', async (t) => {
|
||||
await t.test('resolve', async (t) => {
|
||||
t.plan(1)
|
||||
const { promise, resolve } = PonyPromise[kTestInternals].withResolvers()
|
||||
resolve(true)
|
||||
t.assert.ok(await promise)
|
||||
})
|
||||
await t.test('reject', async (t) => {
|
||||
t.plan(1)
|
||||
const { promise, reject } = PonyPromise[kTestInternals].withResolvers()
|
||||
await t.assert.rejects(async () => {
|
||||
reject(Error('reject'))
|
||||
return promise
|
||||
}, {
|
||||
name: 'Error',
|
||||
message: 'reject'
|
||||
})
|
||||
})
|
||||
await t.test('thenable', async (t) => {
|
||||
t.plan(1)
|
||||
const { promise, resolve } = PonyPromise.withResolvers()
|
||||
resolve(true)
|
||||
promise.then((value) => {
|
||||
t.assert.ok(value)
|
||||
})
|
||||
})
|
||||
})
|
||||
714
node_modules/fastify/test/internals/reply-serialize.test.js
generated
vendored
Normal file
714
node_modules/fastify/test/internals/reply-serialize.test.js
generated
vendored
Normal file
@@ -0,0 +1,714 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const { kReplyCacheSerializeFns, kRouteContext } = require('../../lib/symbols')
|
||||
const Fastify = require('../../fastify')
|
||||
|
||||
function getDefaultSchema () {
|
||||
return {
|
||||
type: 'object',
|
||||
required: ['hello'],
|
||||
properties: {
|
||||
hello: { type: 'string' },
|
||||
world: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getResponseSchema () {
|
||||
return {
|
||||
201: {
|
||||
type: 'object',
|
||||
required: ['status'],
|
||||
properties: {
|
||||
status: {
|
||||
type: 'string',
|
||||
enum: ['ok']
|
||||
},
|
||||
message: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
'4xx': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
status: {
|
||||
type: 'string',
|
||||
enum: ['error']
|
||||
},
|
||||
code: {
|
||||
type: 'integer',
|
||||
minimum: 1
|
||||
},
|
||||
message: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
'3xx': {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
fullName: { type: 'string' },
|
||||
phone: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test('Reply#compileSerializationSchema', async t => {
|
||||
t.plan(4)
|
||||
|
||||
await t.test('Should return a serialization function', async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
t.plan(4)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
const serialize = reply.compileSerializationSchema(getDefaultSchema())
|
||||
const input = { hello: 'world' }
|
||||
t.assert.ok(serialize instanceof Function)
|
||||
t.assert.ok(typeof serialize(input) === 'string')
|
||||
t.assert.strictEqual(serialize(input), JSON.stringify(input))
|
||||
|
||||
try {
|
||||
serialize({ world: 'foo' })
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(err.message, '"hello" is required!')
|
||||
}
|
||||
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
})
|
||||
|
||||
await t.test('Should reuse the serialize fn across multiple invocations - Route without schema',
|
||||
async t => {
|
||||
const fastify = Fastify()
|
||||
let serialize = null
|
||||
let counter = 0
|
||||
|
||||
t.plan(17)
|
||||
|
||||
const schemaObj = getDefaultSchema()
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
const input = { hello: 'world' }
|
||||
counter++
|
||||
if (counter > 1) {
|
||||
const newSerialize = reply.compileSerializationSchema(schemaObj)
|
||||
t.assert.strictEqual(serialize, newSerialize, 'Are the same validate function')
|
||||
serialize = newSerialize
|
||||
} else {
|
||||
t.assert.ok(true, 'build the schema compilation function')
|
||||
serialize = reply.compileSerializationSchema(schemaObj)
|
||||
}
|
||||
|
||||
t.assert.ok(serialize instanceof Function)
|
||||
t.assert.strictEqual(serialize(input), JSON.stringify(input))
|
||||
|
||||
try {
|
||||
serialize({ world: 'foo' })
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(err.message, '"hello" is required!')
|
||||
}
|
||||
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
fastify.inject('/'),
|
||||
fastify.inject('/'),
|
||||
fastify.inject('/'),
|
||||
fastify.inject('/')
|
||||
])
|
||||
|
||||
t.assert.strictEqual(counter, 4)
|
||||
}
|
||||
)
|
||||
|
||||
await t.test('Should use the custom serializer compiler for the route',
|
||||
async t => {
|
||||
const fastify = Fastify()
|
||||
let called = 0
|
||||
const custom = ({ schema, httpStatus, url, method }) => {
|
||||
t.assert.strictEqual(schema, schemaObj)
|
||||
t.assert.strictEqual(url, '/')
|
||||
t.assert.strictEqual(method, 'GET')
|
||||
t.assert.strictEqual(httpStatus, '201')
|
||||
|
||||
return input => {
|
||||
called++
|
||||
t.assert.deepStrictEqual(input, { hello: 'world' })
|
||||
return JSON.stringify(input)
|
||||
}
|
||||
}
|
||||
|
||||
const custom2 = ({ schema, httpStatus, url, method, contentType }) => {
|
||||
t.assert.strictEqual(schema, schemaObj)
|
||||
t.assert.strictEqual(url, '/user')
|
||||
t.assert.strictEqual(method, 'GET')
|
||||
t.assert.strictEqual(httpStatus, '3xx')
|
||||
t.assert.strictEqual(contentType, 'application/json')
|
||||
|
||||
return input => {
|
||||
t.assert.deepStrictEqual(input, { fullName: 'Jone', phone: 1090243795 })
|
||||
return JSON.stringify(input)
|
||||
}
|
||||
}
|
||||
|
||||
t.plan(17)
|
||||
const schemaObj = getDefaultSchema()
|
||||
|
||||
fastify.get('/', { serializerCompiler: custom }, (req, reply) => {
|
||||
const input = { hello: 'world' }
|
||||
const first = reply.compileSerializationSchema(schemaObj, '201')
|
||||
const second = reply.compileSerializationSchema(schemaObj, '201')
|
||||
|
||||
t.assert.strictEqual(first, second)
|
||||
t.assert.ok(first(input), JSON.stringify(input))
|
||||
t.assert.ok(second(input), JSON.stringify(input))
|
||||
t.assert.strictEqual(called, 2)
|
||||
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.get('/user', { serializerCompiler: custom2 }, (req, reply) => {
|
||||
const input = { fullName: 'Jone', phone: 1090243795 }
|
||||
const first = reply.compileSerializationSchema(schemaObj, '3xx', 'application/json')
|
||||
t.assert.ok(first(input), JSON.stringify(input))
|
||||
reply.send(input)
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/user',
|
||||
method: 'GET'
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
await t.test('Should build a WeakMap for cache when called', async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
t.plan(4)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
const input = { hello: 'world' }
|
||||
|
||||
t.assert.strictEqual(reply[kRouteContext][kReplyCacheSerializeFns], null)
|
||||
t.assert.strictEqual(reply.compileSerializationSchema(getDefaultSchema())(input), JSON.stringify(input))
|
||||
t.assert.ok(reply[kRouteContext][kReplyCacheSerializeFns] instanceof WeakMap)
|
||||
t.assert.strictEqual(reply.compileSerializationSchema(getDefaultSchema())(input), JSON.stringify(input))
|
||||
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Reply#getSerializationFunction', async t => {
|
||||
t.plan(3)
|
||||
|
||||
await t.test('Should retrieve the serialization function from the Schema definition',
|
||||
async t => {
|
||||
const fastify = Fastify()
|
||||
const okInput201 = {
|
||||
status: 'ok',
|
||||
message: 'done!'
|
||||
}
|
||||
const notOkInput201 = {
|
||||
message: 'created'
|
||||
}
|
||||
const okInput4xx = {
|
||||
status: 'error',
|
||||
code: 2,
|
||||
message: 'oops!'
|
||||
}
|
||||
const notOkInput4xx = {
|
||||
status: 'error',
|
||||
code: 'something'
|
||||
}
|
||||
const okInput3xx = {
|
||||
fullName: 'Jone',
|
||||
phone: 0
|
||||
}
|
||||
const noOkInput3xx = {
|
||||
fullName: 'Jone',
|
||||
phone: 'phone'
|
||||
}
|
||||
let cached4xx
|
||||
let cached201
|
||||
let cachedJson3xx
|
||||
|
||||
t.plan(13)
|
||||
|
||||
const responseSchema = getResponseSchema()
|
||||
|
||||
fastify.get(
|
||||
'/:id',
|
||||
{
|
||||
params: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
},
|
||||
schema: {
|
||||
response: responseSchema
|
||||
}
|
||||
},
|
||||
(req, reply) => {
|
||||
const { id } = req.params
|
||||
|
||||
if (Number(id) === 1) {
|
||||
const serialize4xx = reply.getSerializationFunction('4xx')
|
||||
const serialize201 = reply.getSerializationFunction(201)
|
||||
const serializeJson3xx = reply.getSerializationFunction('3xx', 'application/json')
|
||||
const serializeUndefined = reply.getSerializationFunction(undefined)
|
||||
|
||||
cached4xx = serialize4xx
|
||||
cached201 = serialize201
|
||||
cachedJson3xx = serializeJson3xx
|
||||
|
||||
t.assert.ok(serialize4xx instanceof Function)
|
||||
t.assert.ok(serialize201 instanceof Function)
|
||||
t.assert.ok(serializeJson3xx instanceof Function)
|
||||
t.assert.strictEqual(serialize4xx(okInput4xx), JSON.stringify(okInput4xx))
|
||||
t.assert.strictEqual(serialize201(okInput201), JSON.stringify(okInput201))
|
||||
t.assert.strictEqual(serializeJson3xx(okInput3xx), JSON.stringify(okInput3xx))
|
||||
t.assert.ok(!serializeUndefined)
|
||||
|
||||
try {
|
||||
serialize4xx(notOkInput4xx)
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(
|
||||
err.message,
|
||||
'The value "something" cannot be converted to an integer.'
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
serialize201(notOkInput201)
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(err.message, '"status" is required!')
|
||||
}
|
||||
|
||||
try {
|
||||
serializeJson3xx(noOkInput3xx)
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(err.message, 'The value "phone" cannot be converted to a number.')
|
||||
}
|
||||
|
||||
reply.status(201).send(okInput201)
|
||||
} else {
|
||||
const serialize201 = reply.getSerializationFunction(201)
|
||||
const serialize4xx = reply.getSerializationFunction('4xx')
|
||||
const serializeJson3xx = reply.getSerializationFunction('3xx', 'application/json')
|
||||
|
||||
t.assert.strictEqual(serialize4xx, cached4xx)
|
||||
t.assert.strictEqual(serialize201, cached201)
|
||||
t.assert.strictEqual(serializeJson3xx, cachedJson3xx)
|
||||
reply.status(401).send(okInput4xx)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
await Promise.all([
|
||||
fastify.inject('/1'),
|
||||
fastify.inject('/2')
|
||||
])
|
||||
}
|
||||
)
|
||||
|
||||
await t.test('Should retrieve the serialization function from the cached one',
|
||||
async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
const schemaObj = getDefaultSchema()
|
||||
|
||||
const okInput = {
|
||||
hello: 'world',
|
||||
world: 'done!'
|
||||
}
|
||||
const notOkInput = {
|
||||
world: 'done!'
|
||||
}
|
||||
let cached
|
||||
|
||||
t.plan(6)
|
||||
|
||||
fastify.get(
|
||||
'/:id',
|
||||
{
|
||||
params: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
(req, reply) => {
|
||||
const { id } = req.params
|
||||
|
||||
if (Number(id) === 1) {
|
||||
const serialize = reply.compileSerializationSchema(schemaObj)
|
||||
|
||||
t.assert.ok(serialize instanceof Function)
|
||||
t.assert.strictEqual(serialize(okInput), JSON.stringify(okInput))
|
||||
|
||||
try {
|
||||
serialize(notOkInput)
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(err.message, '"hello" is required!')
|
||||
}
|
||||
|
||||
cached = serialize
|
||||
} else {
|
||||
const serialize = reply.getSerializationFunction(schemaObj)
|
||||
|
||||
t.assert.strictEqual(serialize, cached)
|
||||
t.assert.strictEqual(serialize(okInput), JSON.stringify(okInput))
|
||||
|
||||
try {
|
||||
serialize(notOkInput)
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(err.message, '"hello" is required!')
|
||||
}
|
||||
}
|
||||
|
||||
reply.status(201).send(okInput)
|
||||
}
|
||||
)
|
||||
|
||||
await Promise.all([
|
||||
fastify.inject('/1'),
|
||||
fastify.inject('/2')
|
||||
])
|
||||
}
|
||||
)
|
||||
|
||||
await t.test('Should not instantiate a WeakMap if it is not needed', async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
t.plan(4)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.assert.ok(!reply.getSerializationFunction(getDefaultSchema()))
|
||||
t.assert.strictEqual(reply[kRouteContext][kReplyCacheSerializeFns], null)
|
||||
t.assert.ok(!reply.getSerializationFunction('200'))
|
||||
t.assert.strictEqual(reply[kRouteContext][kReplyCacheSerializeFns], null)
|
||||
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Reply#serializeInput', async t => {
|
||||
t.plan(6)
|
||||
|
||||
await t.test(
|
||||
'Should throw if missed serialization function from HTTP status',
|
||||
async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
t.plan(2)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.serializeInput({}, 201)
|
||||
})
|
||||
|
||||
const result = await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
|
||||
t.assert.strictEqual(result.statusCode, 500)
|
||||
t.assert.deepStrictEqual(result.json(), {
|
||||
statusCode: 500,
|
||||
code: 'FST_ERR_MISSING_SERIALIZATION_FN',
|
||||
error: 'Internal Server Error',
|
||||
message: 'Missing serialization function. Key "201"'
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
await t.test(
|
||||
'Should throw if missed serialization function from HTTP status with specific content type',
|
||||
async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
t.plan(2)
|
||||
|
||||
fastify.get('/', {
|
||||
schema: {
|
||||
response: {
|
||||
'3xx': {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
fullName: { type: 'string' },
|
||||
phone: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, (req, reply) => {
|
||||
reply.serializeInput({}, '3xx', 'application/vnd.v1+json')
|
||||
})
|
||||
|
||||
const result = await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
|
||||
t.assert.strictEqual(result.statusCode, 500)
|
||||
t.assert.deepStrictEqual(result.json(), {
|
||||
statusCode: 500,
|
||||
code: 'FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN',
|
||||
error: 'Internal Server Error',
|
||||
message: 'Missing serialization function. Key "3xx:application/vnd.v1+json"'
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
await t.test('Should use a serializer fn from HTTP status', async t => {
|
||||
const fastify = Fastify()
|
||||
const okInput201 = {
|
||||
status: 'ok',
|
||||
message: 'done!'
|
||||
}
|
||||
const notOkInput201 = {
|
||||
message: 'created'
|
||||
}
|
||||
const okInput4xx = {
|
||||
status: 'error',
|
||||
code: 2,
|
||||
message: 'oops!'
|
||||
}
|
||||
const notOkInput4xx = {
|
||||
status: 'error',
|
||||
code: 'something'
|
||||
}
|
||||
const okInput3xx = {
|
||||
fullName: 'Jone',
|
||||
phone: 0
|
||||
}
|
||||
const noOkInput3xx = {
|
||||
fullName: 'Jone',
|
||||
phone: 'phone'
|
||||
}
|
||||
|
||||
t.plan(6)
|
||||
|
||||
fastify.get(
|
||||
'/',
|
||||
{
|
||||
params: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
},
|
||||
schema: {
|
||||
response: getResponseSchema()
|
||||
}
|
||||
},
|
||||
(req, reply) => {
|
||||
t.assert.strictEqual(
|
||||
reply.serializeInput(okInput4xx, '4xx'),
|
||||
JSON.stringify(okInput4xx)
|
||||
)
|
||||
t.assert.strictEqual(
|
||||
reply.serializeInput(okInput201, 201),
|
||||
JSON.stringify(okInput201)
|
||||
)
|
||||
|
||||
t.assert.strictEqual(
|
||||
reply.serializeInput(okInput3xx, {}, '3xx', 'application/json'),
|
||||
JSON.stringify(okInput3xx)
|
||||
)
|
||||
|
||||
try {
|
||||
reply.serializeInput(noOkInput3xx, '3xx', 'application/json')
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(err.message, 'The value "phone" cannot be converted to a number.')
|
||||
}
|
||||
|
||||
try {
|
||||
reply.serializeInput(notOkInput4xx, '4xx')
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(
|
||||
err.message,
|
||||
'The value "something" cannot be converted to an integer.'
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
reply.serializeInput(notOkInput201, 201)
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(err.message, '"status" is required!')
|
||||
}
|
||||
|
||||
reply.status(204).send('')
|
||||
}
|
||||
)
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
})
|
||||
|
||||
await t.test(
|
||||
'Should compile a serializer out of a schema if serializer fn missed',
|
||||
async t => {
|
||||
let compilerCalled = 0
|
||||
let serializerCalled = 0
|
||||
const testInput = { hello: 'world' }
|
||||
const schemaObj = getDefaultSchema()
|
||||
const fastify = Fastify()
|
||||
const serializerCompiler = ({ schema, httpStatus, method, url }) => {
|
||||
t.assert.strictEqual(schema, schemaObj)
|
||||
t.assert.ok(!httpStatus)
|
||||
t.assert.strictEqual(method, 'GET')
|
||||
t.assert.strictEqual(url, '/')
|
||||
|
||||
compilerCalled++
|
||||
return input => {
|
||||
t.assert.strictEqual(input, testInput)
|
||||
serializerCalled++
|
||||
return JSON.stringify(input)
|
||||
}
|
||||
}
|
||||
|
||||
t.plan(10)
|
||||
|
||||
fastify.get('/', { serializerCompiler }, (req, reply) => {
|
||||
t.assert.strictEqual(
|
||||
reply.serializeInput(testInput, schemaObj),
|
||||
JSON.stringify(testInput)
|
||||
)
|
||||
|
||||
t.assert.strictEqual(
|
||||
reply.serializeInput(testInput, schemaObj),
|
||||
JSON.stringify(testInput)
|
||||
)
|
||||
|
||||
reply.status(201).send(testInput)
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
|
||||
t.assert.strictEqual(compilerCalled, 1)
|
||||
t.assert.strictEqual(serializerCalled, 2)
|
||||
}
|
||||
)
|
||||
|
||||
await t.test('Should use a cached serializer fn', async t => {
|
||||
let compilerCalled = 0
|
||||
let serializerCalled = 0
|
||||
let cached
|
||||
const testInput = { hello: 'world' }
|
||||
const schemaObj = getDefaultSchema()
|
||||
const fastify = Fastify()
|
||||
const serializer = input => {
|
||||
t.assert.strictEqual(input, testInput)
|
||||
serializerCalled++
|
||||
return JSON.stringify(input)
|
||||
}
|
||||
const serializerCompiler = ({ schema, httpStatus, method, url }) => {
|
||||
t.assert.strictEqual(schema, schemaObj)
|
||||
t.assert.ok(!httpStatus)
|
||||
t.assert.strictEqual(method, 'GET')
|
||||
t.assert.strictEqual(url, '/')
|
||||
|
||||
compilerCalled++
|
||||
return serializer
|
||||
}
|
||||
|
||||
t.plan(12)
|
||||
|
||||
fastify.get('/', { serializerCompiler }, (req, reply) => {
|
||||
t.assert.strictEqual(
|
||||
reply.serializeInput(testInput, schemaObj),
|
||||
JSON.stringify(testInput)
|
||||
)
|
||||
|
||||
cached = reply.getSerializationFunction(schemaObj)
|
||||
|
||||
t.assert.strictEqual(
|
||||
reply.serializeInput(testInput, schemaObj),
|
||||
cached(testInput)
|
||||
)
|
||||
|
||||
reply.status(201).send(testInput)
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
|
||||
t.assert.strictEqual(cached, serializer)
|
||||
t.assert.strictEqual(compilerCalled, 1)
|
||||
t.assert.strictEqual(serializerCalled, 3)
|
||||
})
|
||||
|
||||
await t.test('Should instantiate a WeakMap after first call', async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
t.plan(3)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
const input = { hello: 'world' }
|
||||
t.assert.strictEqual(reply[kRouteContext][kReplyCacheSerializeFns], null)
|
||||
t.assert.strictEqual(reply.serializeInput(input, getDefaultSchema()), JSON.stringify(input))
|
||||
t.assert.ok(reply[kRouteContext][kReplyCacheSerializeFns] instanceof WeakMap)
|
||||
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
})
|
||||
})
|
||||
1901
node_modules/fastify/test/internals/reply.test.js
generated
vendored
Normal file
1901
node_modules/fastify/test/internals/reply.test.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
133
node_modules/fastify/test/internals/req-id-gen-factory.test.js
generated
vendored
Normal file
133
node_modules/fastify/test/internals/req-id-gen-factory.test.js
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const { reqIdGenFactory } = require('../../lib/reqIdGenFactory')
|
||||
|
||||
test('should create incremental ids deterministically', t => {
|
||||
t.plan(1)
|
||||
const reqIdGen = reqIdGenFactory()
|
||||
|
||||
for (let i = 1; i < 1e4; ++i) {
|
||||
if (reqIdGen() !== 'req-' + i.toString(36)) {
|
||||
t.assert.fail()
|
||||
break
|
||||
}
|
||||
}
|
||||
t.assert.ok(true)
|
||||
})
|
||||
|
||||
test('should have prefix "req-"', t => {
|
||||
t.plan(1)
|
||||
const reqIdGen = reqIdGenFactory()
|
||||
|
||||
t.assert.ok(reqIdGen().startsWith('req-'))
|
||||
})
|
||||
|
||||
test('different id generator functions should have separate internal counters', t => {
|
||||
t.plan(5)
|
||||
const reqIdGenA = reqIdGenFactory()
|
||||
const reqIdGenB = reqIdGenFactory()
|
||||
|
||||
t.assert.strictEqual(reqIdGenA(), 'req-1')
|
||||
t.assert.strictEqual(reqIdGenA(), 'req-2')
|
||||
t.assert.strictEqual(reqIdGenB(), 'req-1')
|
||||
t.assert.strictEqual(reqIdGenA(), 'req-3')
|
||||
t.assert.strictEqual(reqIdGenB(), 'req-2')
|
||||
})
|
||||
|
||||
test('should start counting with 1', t => {
|
||||
t.plan(1)
|
||||
const reqIdGen = reqIdGenFactory()
|
||||
|
||||
t.assert.strictEqual(reqIdGen(), 'req-1')
|
||||
})
|
||||
|
||||
test('should handle requestIdHeader and return provided id in header', t => {
|
||||
t.plan(1)
|
||||
|
||||
const reqIdGen = reqIdGenFactory('id')
|
||||
|
||||
t.assert.strictEqual(reqIdGen({ headers: { id: '1337' } }), '1337')
|
||||
})
|
||||
|
||||
test('should handle requestIdHeader and fallback if id is not provided in header', t => {
|
||||
t.plan(1)
|
||||
|
||||
const reqIdGen = reqIdGenFactory('id')
|
||||
|
||||
t.assert.strictEqual(reqIdGen({ headers: { notId: '1337' } }), 'req-1')
|
||||
})
|
||||
|
||||
test('should handle requestIdHeader and increment internal counter if no header was provided', t => {
|
||||
t.plan(4)
|
||||
|
||||
const reqIdGen = reqIdGenFactory('id')
|
||||
|
||||
t.assert.strictEqual(reqIdGen({ headers: {} }), 'req-1')
|
||||
t.assert.strictEqual(reqIdGen({ headers: {} }), 'req-2')
|
||||
t.assert.strictEqual(reqIdGen({ headers: { id: '1337' } }), '1337')
|
||||
t.assert.strictEqual(reqIdGen({ headers: {} }), 'req-3')
|
||||
})
|
||||
|
||||
test('should use optGenReqId to generate ids', t => {
|
||||
t.plan(4)
|
||||
|
||||
let i = 1
|
||||
let gotCalled = false
|
||||
function optGenReqId () {
|
||||
gotCalled = true
|
||||
return (i++).toString(16)
|
||||
}
|
||||
const reqIdGen = reqIdGenFactory(undefined, optGenReqId)
|
||||
|
||||
t.assert.strictEqual(gotCalled, false)
|
||||
t.assert.strictEqual(reqIdGen(), '1')
|
||||
t.assert.strictEqual(gotCalled, true)
|
||||
t.assert.strictEqual(reqIdGen(), '2')
|
||||
})
|
||||
|
||||
test('should use optGenReqId to generate ids if requestIdHeader is used but not provided', t => {
|
||||
t.plan(4)
|
||||
|
||||
let i = 1
|
||||
let gotCalled = false
|
||||
function optGenReqId () {
|
||||
gotCalled = true
|
||||
return (i++).toString(16)
|
||||
}
|
||||
const reqIdGen = reqIdGenFactory('reqId', optGenReqId)
|
||||
|
||||
t.assert.strictEqual(gotCalled, false)
|
||||
t.assert.strictEqual(reqIdGen({ headers: {} }), '1')
|
||||
t.assert.strictEqual(gotCalled, true)
|
||||
t.assert.strictEqual(reqIdGen({ headers: {} }), '2')
|
||||
})
|
||||
|
||||
test('should not use optGenReqId to generate ids if requestIdHeader is used and provided', t => {
|
||||
t.plan(2)
|
||||
|
||||
function optGenReqId () {
|
||||
t.assert.fail()
|
||||
}
|
||||
const reqIdGen = reqIdGenFactory('reqId', optGenReqId)
|
||||
|
||||
t.assert.strictEqual(reqIdGen({ headers: { reqId: 'r1' } }), 'r1')
|
||||
t.assert.strictEqual(reqIdGen({ headers: { reqId: 'r2' } }), 'r2')
|
||||
})
|
||||
|
||||
test('should fallback to use optGenReqId to generate ids if requestIdHeader is sometimes provided', t => {
|
||||
t.plan(4)
|
||||
|
||||
let i = 1
|
||||
let gotCalled = false
|
||||
function optGenReqId () {
|
||||
gotCalled = true
|
||||
return (i++).toString(16)
|
||||
}
|
||||
const reqIdGen = reqIdGenFactory('reqId', optGenReqId)
|
||||
|
||||
t.assert.strictEqual(reqIdGen({ headers: { reqId: 'r1' } }), 'r1')
|
||||
t.assert.strictEqual(gotCalled, false)
|
||||
t.assert.strictEqual(reqIdGen({ headers: {} }), '1')
|
||||
t.assert.strictEqual(gotCalled, true)
|
||||
})
|
||||
1402
node_modules/fastify/test/internals/request-validate.test.js
generated
vendored
Normal file
1402
node_modules/fastify/test/internals/request-validate.test.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
506
node_modules/fastify/test/internals/request.test.js
generated
vendored
Normal file
506
node_modules/fastify/test/internals/request.test.js
generated
vendored
Normal file
@@ -0,0 +1,506 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
|
||||
const Request = require('../../lib/request')
|
||||
const Context = require('../../lib/context')
|
||||
const {
|
||||
kReply,
|
||||
kRequest,
|
||||
kOptions
|
||||
} = require('../../lib/symbols')
|
||||
|
||||
process.removeAllListeners('warning')
|
||||
|
||||
test('Regular request', t => {
|
||||
const headers = {
|
||||
host: 'hostname'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
const context = new Context({
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['hello'],
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
config: {
|
||||
some: 'config',
|
||||
url: req.url,
|
||||
method: req.method
|
||||
},
|
||||
server: {
|
||||
[kReply]: {},
|
||||
[kRequest]: Request,
|
||||
[kOptions]: {
|
||||
requestIdLogLabel: 'reqId'
|
||||
},
|
||||
server: {}
|
||||
}
|
||||
})
|
||||
req.connection = req.socket
|
||||
const request = new Request('id', 'params', req, 'query', 'log', context)
|
||||
t.assert.ok(request instanceof Request)
|
||||
t.assert.ok(request.validateInput instanceof Function)
|
||||
t.assert.ok(request.getValidationFunction instanceof Function)
|
||||
t.assert.ok(request.compileValidationSchema instanceof Function)
|
||||
t.assert.strictEqual(request.id, 'id')
|
||||
t.assert.strictEqual(request.params, 'params')
|
||||
t.assert.strictEqual(request.raw, req)
|
||||
t.assert.strictEqual(request.query, 'query')
|
||||
t.assert.strictEqual(request.headers, headers)
|
||||
t.assert.strictEqual(request.log, 'log')
|
||||
t.assert.strictEqual(request.ip, 'ip')
|
||||
t.assert.strictEqual(request.ips, undefined)
|
||||
t.assert.strictEqual(request.host, 'hostname')
|
||||
t.assert.strictEqual(request.body, undefined)
|
||||
t.assert.strictEqual(request.method, 'GET')
|
||||
t.assert.strictEqual(request.url, '/')
|
||||
t.assert.strictEqual(request.originalUrl, '/')
|
||||
t.assert.strictEqual(request.socket, req.socket)
|
||||
t.assert.strictEqual(request.protocol, 'http')
|
||||
// Aim to not bad property keys (including Symbols)
|
||||
t.assert.ok(!('undefined' in request))
|
||||
})
|
||||
|
||||
test('Request with undefined config', t => {
|
||||
const headers = {
|
||||
host: 'hostname'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
const context = new Context({
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['hello'],
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
server: {
|
||||
[kReply]: {},
|
||||
[kRequest]: Request,
|
||||
[kOptions]: {
|
||||
requestIdLogLabel: 'reqId'
|
||||
},
|
||||
server: {}
|
||||
}
|
||||
})
|
||||
req.connection = req.socket
|
||||
const request = new Request('id', 'params', req, 'query', 'log', context)
|
||||
t.assert.ok(request, Request)
|
||||
t.assert.ok(request.validateInput, Function)
|
||||
t.assert.ok(request.getValidationFunction, Function)
|
||||
t.assert.ok(request.compileValidationSchema, Function)
|
||||
t.assert.strictEqual(request.id, 'id')
|
||||
t.assert.strictEqual(request.params, 'params')
|
||||
t.assert.strictEqual(request.raw, req)
|
||||
t.assert.strictEqual(request.query, 'query')
|
||||
t.assert.strictEqual(request.headers, headers)
|
||||
t.assert.strictEqual(request.log, 'log')
|
||||
t.assert.strictEqual(request.ip, 'ip')
|
||||
t.assert.strictEqual(request.ips, undefined)
|
||||
t.assert.strictEqual(request.hostname, 'hostname')
|
||||
t.assert.strictEqual(request.body, undefined)
|
||||
t.assert.strictEqual(request.method, 'GET')
|
||||
t.assert.strictEqual(request.url, '/')
|
||||
t.assert.strictEqual(request.originalUrl, '/')
|
||||
t.assert.strictEqual(request.socket, req.socket)
|
||||
t.assert.strictEqual(request.protocol, 'http')
|
||||
|
||||
// Aim to not bad property keys (including Symbols)
|
||||
t.assert.ok(!('undefined' in request))
|
||||
})
|
||||
|
||||
test('Regular request - hostname from authority', t => {
|
||||
t.plan(3)
|
||||
const headers = {
|
||||
':authority': 'authority'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
const context = new Context({
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['hello'],
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
config: {
|
||||
some: 'config',
|
||||
url: req.url,
|
||||
method: req.method
|
||||
},
|
||||
server: {
|
||||
[kReply]: {},
|
||||
[kRequest]: Request,
|
||||
[kOptions]: {
|
||||
requestIdLogLabel: 'reqId'
|
||||
},
|
||||
server: {}
|
||||
}
|
||||
})
|
||||
|
||||
const request = new Request('id', 'params', req, 'query', 'log', context)
|
||||
t.assert.ok(request instanceof Request)
|
||||
t.assert.strictEqual(request.host, 'authority')
|
||||
t.assert.strictEqual(request.port, null)
|
||||
})
|
||||
|
||||
test('Regular request - host header has precedence over authority', t => {
|
||||
t.plan(3)
|
||||
const headers = {
|
||||
host: 'hostname',
|
||||
':authority': 'authority'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
const context = new Context({
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['hello'],
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
config: {
|
||||
some: 'config',
|
||||
url: req.url,
|
||||
method: req.method
|
||||
},
|
||||
server: {
|
||||
[kReply]: {},
|
||||
[kRequest]: Request,
|
||||
[kOptions]: {
|
||||
requestIdLogLabel: 'reqId'
|
||||
},
|
||||
server: {}
|
||||
}
|
||||
})
|
||||
const request = new Request('id', 'params', req, 'query', 'log', context)
|
||||
t.assert.ok(request instanceof Request)
|
||||
t.assert.strictEqual(request.host, 'hostname')
|
||||
t.assert.strictEqual(request.port, null)
|
||||
})
|
||||
|
||||
test('Request with trust proxy', t => {
|
||||
t.plan(18)
|
||||
const headers = {
|
||||
'x-forwarded-for': '2.2.2.2, 1.1.1.1',
|
||||
'x-forwarded-host': 'example.com'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
const context = new Context({
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['hello'],
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
config: {
|
||||
some: 'config',
|
||||
url: req.url,
|
||||
method: req.method
|
||||
},
|
||||
server: {
|
||||
[kReply]: {},
|
||||
[kRequest]: Request,
|
||||
[kOptions]: {
|
||||
requestIdLogLabel: 'reqId'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log', context)
|
||||
t.assert.ok(request instanceof TpRequest)
|
||||
t.assert.strictEqual(request.id, 'id')
|
||||
t.assert.strictEqual(request.params, 'params')
|
||||
t.assert.deepStrictEqual(request.raw, req)
|
||||
t.assert.strictEqual(request.query, 'query')
|
||||
t.assert.strictEqual(request.headers, headers)
|
||||
t.assert.strictEqual(request.log, 'log')
|
||||
t.assert.strictEqual(request.ip, '2.2.2.2')
|
||||
t.assert.deepStrictEqual(request.ips, ['ip', '1.1.1.1', '2.2.2.2'])
|
||||
t.assert.strictEqual(request.host, 'example.com')
|
||||
t.assert.strictEqual(request.body, undefined)
|
||||
t.assert.strictEqual(request.method, 'GET')
|
||||
t.assert.strictEqual(request.url, '/')
|
||||
t.assert.strictEqual(request.socket, req.socket)
|
||||
t.assert.strictEqual(request.protocol, 'http')
|
||||
t.assert.ok(request.validateInput instanceof Function)
|
||||
t.assert.ok(request.getValidationFunction instanceof Function)
|
||||
t.assert.ok(request.compileValidationSchema instanceof Function)
|
||||
})
|
||||
|
||||
test('Request with trust proxy, encrypted', t => {
|
||||
t.plan(2)
|
||||
const headers = {
|
||||
'x-forwarded-for': '2.2.2.2, 1.1.1.1',
|
||||
'x-forwarded-host': 'example.com'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip', encrypted: true },
|
||||
headers
|
||||
}
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log')
|
||||
t.assert.ok(request instanceof TpRequest)
|
||||
t.assert.strictEqual(request.protocol, 'https')
|
||||
})
|
||||
|
||||
test('Request with trust proxy - no x-forwarded-host header', t => {
|
||||
t.plan(2)
|
||||
const headers = {
|
||||
'x-forwarded-for': '2.2.2.2, 1.1.1.1',
|
||||
host: 'hostname'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
const context = new Context({
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['hello'],
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
config: {
|
||||
some: 'config',
|
||||
url: req.url,
|
||||
method: req.method
|
||||
},
|
||||
server: {
|
||||
[kReply]: {},
|
||||
[kRequest]: Request,
|
||||
[kOptions]: {
|
||||
requestIdLogLabel: 'reqId'
|
||||
},
|
||||
server: {}
|
||||
}
|
||||
})
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log', context)
|
||||
t.assert.ok(request instanceof TpRequest)
|
||||
t.assert.strictEqual(request.host, 'hostname')
|
||||
})
|
||||
|
||||
test('Request with trust proxy - no x-forwarded-host header and fallback to authority', t => {
|
||||
t.plan(2)
|
||||
const headers = {
|
||||
'x-forwarded-for': '2.2.2.2, 1.1.1.1',
|
||||
':authority': 'authority'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
const context = new Context({
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['hello'],
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
config: {
|
||||
some: 'config',
|
||||
url: req.url,
|
||||
method: req.method
|
||||
},
|
||||
server: {
|
||||
[kReply]: {},
|
||||
[kRequest]: Request,
|
||||
[kOptions]: {
|
||||
requestIdLogLabel: 'reqId'
|
||||
},
|
||||
server: {}
|
||||
}
|
||||
})
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log', context)
|
||||
t.assert.ok(request instanceof TpRequest)
|
||||
t.assert.strictEqual(request.host, 'authority')
|
||||
})
|
||||
|
||||
test('Request with trust proxy - x-forwarded-host header has precedence over host', t => {
|
||||
t.plan(2)
|
||||
const headers = {
|
||||
'x-forwarded-for': ' 2.2.2.2, 1.1.1.1',
|
||||
'x-forwarded-host': 'example.com',
|
||||
host: 'hostname'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log')
|
||||
t.assert.ok(request instanceof TpRequest)
|
||||
t.assert.strictEqual(request.host, 'example.com')
|
||||
})
|
||||
|
||||
test('Request with trust proxy - handles multiple entries in x-forwarded-host/proto', t => {
|
||||
t.plan(3)
|
||||
const headers = {
|
||||
'x-forwarded-host': 'example2.com, example.com',
|
||||
'x-forwarded-proto': 'http, https'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log')
|
||||
t.assert.ok(request instanceof TpRequest)
|
||||
t.assert.strictEqual(request.host, 'example.com')
|
||||
t.assert.strictEqual(request.protocol, 'https')
|
||||
})
|
||||
|
||||
test('Request with trust proxy - plain', t => {
|
||||
t.plan(1)
|
||||
const headers = {
|
||||
'x-forwarded-for': '2.2.2.2, 1.1.1.1',
|
||||
'x-forwarded-host': 'example.com'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log')
|
||||
t.assert.deepStrictEqual(request.protocol, 'http')
|
||||
})
|
||||
|
||||
test('Request with undefined socket', t => {
|
||||
t.plan(18)
|
||||
const headers = {
|
||||
host: 'hostname'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: undefined,
|
||||
headers
|
||||
}
|
||||
const context = new Context({
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['hello'],
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
config: {
|
||||
some: 'config',
|
||||
url: req.url,
|
||||
method: req.method
|
||||
},
|
||||
server: {
|
||||
[kReply]: {},
|
||||
[kRequest]: Request,
|
||||
[kOptions]: {
|
||||
requestIdLogLabel: 'reqId'
|
||||
},
|
||||
server: {}
|
||||
}
|
||||
})
|
||||
const request = new Request('id', 'params', req, 'query', 'log', context)
|
||||
t.assert.ok(request instanceof Request)
|
||||
t.assert.strictEqual(request.id, 'id')
|
||||
t.assert.strictEqual(request.params, 'params')
|
||||
t.assert.deepStrictEqual(request.raw, req)
|
||||
t.assert.strictEqual(request.query, 'query')
|
||||
t.assert.strictEqual(request.headers, headers)
|
||||
t.assert.strictEqual(request.log, 'log')
|
||||
t.assert.strictEqual(request.ip, undefined)
|
||||
t.assert.strictEqual(request.ips, undefined)
|
||||
t.assert.strictEqual(request.host, 'hostname')
|
||||
t.assert.deepStrictEqual(request.body, undefined)
|
||||
t.assert.strictEqual(request.method, 'GET')
|
||||
t.assert.strictEqual(request.url, '/')
|
||||
t.assert.strictEqual(request.protocol, undefined)
|
||||
t.assert.deepStrictEqual(request.socket, req.socket)
|
||||
t.assert.ok(request.validateInput instanceof Function)
|
||||
t.assert.ok(request.getValidationFunction instanceof Function)
|
||||
t.assert.ok(request.compileValidationSchema instanceof Function)
|
||||
})
|
||||
|
||||
test('Request with trust proxy and undefined socket', t => {
|
||||
t.plan(1)
|
||||
const headers = {
|
||||
'x-forwarded-for': '2.2.2.2, 1.1.1.1',
|
||||
'x-forwarded-host': 'example.com'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: undefined,
|
||||
headers
|
||||
}
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log')
|
||||
t.assert.deepStrictEqual(request.protocol, undefined)
|
||||
})
|
||||
91
node_modules/fastify/test/internals/server.test.js
generated
vendored
Normal file
91
node_modules/fastify/test/internals/server.test.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const proxyquire = require('proxyquire')
|
||||
|
||||
const Fastify = require('../../fastify')
|
||||
const { createServer } = require('../../lib/server')
|
||||
|
||||
const handler = (req, res) => {
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' })
|
||||
res.end(JSON.stringify({ data: 'Hello World!' }))
|
||||
}
|
||||
|
||||
test('start listening', async t => {
|
||||
const { server, listen } = createServer({}, handler)
|
||||
await listen.call(Fastify(), { port: 0, host: 'localhost' })
|
||||
server.close()
|
||||
t.assert.ok(true, 'server started')
|
||||
})
|
||||
|
||||
test('DNS errors does not stop the main server on localhost - promise interface', async t => {
|
||||
const { createServer } = proxyquire('../../lib/server', {
|
||||
'node:dns': {
|
||||
lookup: (hostname, options, cb) => {
|
||||
cb(new Error('DNS error'))
|
||||
}
|
||||
}
|
||||
})
|
||||
const { server, listen } = createServer({}, handler)
|
||||
await listen.call(Fastify(), { port: 0, host: 'localhost' })
|
||||
server.close()
|
||||
t.assert.ok(true, 'server started')
|
||||
})
|
||||
|
||||
test('DNS errors does not stop the main server on localhost - callback interface', (t, done) => {
|
||||
t.plan(2)
|
||||
const { createServer } = proxyquire('../../lib/server', {
|
||||
'node:dns': {
|
||||
lookup: (hostname, options, cb) => {
|
||||
cb(new Error('DNS error'))
|
||||
}
|
||||
}
|
||||
})
|
||||
const { server, listen } = createServer({}, handler)
|
||||
listen.call(Fastify(), { port: 0, host: 'localhost' }, (err) => {
|
||||
t.assert.ifError(err)
|
||||
server.close()
|
||||
t.assert.ok(true, 'server started')
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
test('DNS returns empty binding', (t, done) => {
|
||||
t.plan(2)
|
||||
const { createServer } = proxyquire('../../lib/server', {
|
||||
'node:dns': {
|
||||
lookup: (hostname, options, cb) => {
|
||||
cb(null, [])
|
||||
}
|
||||
}
|
||||
})
|
||||
const { server, listen } = createServer({}, handler)
|
||||
listen.call(Fastify(), { port: 0, host: 'localhost' }, (err) => {
|
||||
t.assert.ifError(err)
|
||||
server.close()
|
||||
t.assert.ok(true, 'server started')
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
test('DNS returns more than two binding', (t, done) => {
|
||||
t.plan(2)
|
||||
const { createServer } = proxyquire('../../lib/server', {
|
||||
'node:dns': {
|
||||
lookup: (hostname, options, cb) => {
|
||||
cb(null, [
|
||||
{ address: '::1', family: 6 },
|
||||
{ address: '127.0.0.1', family: 4 },
|
||||
{ address: '0.0.0.0', family: 4 }
|
||||
])
|
||||
}
|
||||
}
|
||||
})
|
||||
const { server, listen } = createServer({}, handler)
|
||||
listen.call(Fastify(), { port: 0, host: 'localhost' }, (err) => {
|
||||
t.assert.ifError(err)
|
||||
server.close()
|
||||
t.assert.ok(true, 'server started')
|
||||
done()
|
||||
})
|
||||
})
|
||||
352
node_modules/fastify/test/internals/validation.test.js
generated
vendored
Normal file
352
node_modules/fastify/test/internals/validation.test.js
generated
vendored
Normal file
@@ -0,0 +1,352 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
|
||||
const Ajv = require('ajv')
|
||||
const ajv = new Ajv({ coerceTypes: true })
|
||||
|
||||
const validation = require('../../lib/validation')
|
||||
const { normalizeSchema } = require('../../lib/schemas')
|
||||
const symbols = require('../../lib/validation').symbols
|
||||
const { kSchemaVisited } = require('../../lib/symbols')
|
||||
|
||||
test('Symbols', t => {
|
||||
t.plan(5)
|
||||
t.assert.strictEqual(typeof symbols.responseSchema, 'symbol')
|
||||
t.assert.strictEqual(typeof symbols.bodySchema, 'symbol')
|
||||
t.assert.strictEqual(typeof symbols.querystringSchema, 'symbol')
|
||||
t.assert.strictEqual(typeof symbols.paramsSchema, 'symbol')
|
||||
t.assert.strictEqual(typeof symbols.headersSchema, 'symbol')
|
||||
})
|
||||
|
||||
;['compileSchemasForValidation',
|
||||
'compileSchemasForSerialization'].forEach(func => {
|
||||
test(`${func} schema - missing schema`, t => {
|
||||
t.plan(2)
|
||||
const context = {}
|
||||
validation[func](context)
|
||||
t.assert.strictEqual(typeof context[symbols.bodySchema], 'undefined')
|
||||
t.assert.strictEqual(typeof context[symbols.responseSchema], 'undefined')
|
||||
})
|
||||
|
||||
test(`${func} schema - missing output schema`, t => {
|
||||
t.plan(1)
|
||||
const context = { schema: {} }
|
||||
validation[func](context, null)
|
||||
t.assert.strictEqual(typeof context[symbols.responseSchema], 'undefined')
|
||||
})
|
||||
})
|
||||
|
||||
test('build schema - output schema', t => {
|
||||
t.plan(2)
|
||||
const opts = {
|
||||
schema: {
|
||||
response: {
|
||||
'2xx': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
},
|
||||
201: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
validation.compileSchemasForSerialization(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))
|
||||
t.assert.strictEqual(typeof opts[symbols.responseSchema]['2xx'], 'function')
|
||||
t.assert.strictEqual(typeof opts[symbols.responseSchema]['201'], 'function')
|
||||
})
|
||||
|
||||
test('build schema - body schema', t => {
|
||||
t.plan(1)
|
||||
const opts = {
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))
|
||||
t.assert.strictEqual(typeof opts[symbols.bodySchema], 'function')
|
||||
})
|
||||
|
||||
test('build schema - body with multiple content type schemas', t => {
|
||||
t.plan(2)
|
||||
const opts = {
|
||||
schema: {
|
||||
body: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
'text/plain': {
|
||||
schema: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))
|
||||
t.assert.ok(opts[symbols.bodySchema]['application/json'], 'function')
|
||||
t.assert.ok(opts[symbols.bodySchema]['text/plain'], 'function')
|
||||
})
|
||||
|
||||
test('build schema - avoid repeated normalize schema', t => {
|
||||
t.plan(3)
|
||||
const serverConfig = {}
|
||||
const opts = {
|
||||
schema: {
|
||||
query: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
opts.schema = normalizeSchema(opts.schema, serverConfig)
|
||||
t.assert.notStrictEqual(kSchemaVisited, undefined)
|
||||
t.assert.strictEqual(opts.schema[kSchemaVisited], true)
|
||||
t.assert.strictEqual(opts.schema, normalizeSchema(opts.schema, serverConfig))
|
||||
})
|
||||
|
||||
test('build schema - query schema', t => {
|
||||
t.plan(2)
|
||||
const serverConfig = {}
|
||||
const opts = {
|
||||
schema: {
|
||||
query: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
opts.schema = normalizeSchema(opts.schema, serverConfig)
|
||||
validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))
|
||||
t.assert.ok(typeof opts[symbols.querystringSchema].schema.type === 'string')
|
||||
t.assert.strictEqual(typeof opts[symbols.querystringSchema], 'function')
|
||||
})
|
||||
|
||||
test('build schema - query schema abbreviated', t => {
|
||||
t.plan(2)
|
||||
const serverConfig = {}
|
||||
const opts = {
|
||||
schema: {
|
||||
query: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
opts.schema = normalizeSchema(opts.schema, serverConfig)
|
||||
validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))
|
||||
t.assert.ok(typeof opts[symbols.querystringSchema].schema.type === 'string')
|
||||
t.assert.strictEqual(typeof opts[symbols.querystringSchema], 'function')
|
||||
})
|
||||
|
||||
test('build schema - querystring schema', t => {
|
||||
t.plan(2)
|
||||
const opts = {
|
||||
schema: {
|
||||
querystring: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))
|
||||
t.assert.ok(typeof opts[symbols.querystringSchema].schema.type === 'string')
|
||||
t.assert.strictEqual(typeof opts[symbols.querystringSchema], 'function')
|
||||
})
|
||||
|
||||
test('build schema - querystring schema abbreviated', t => {
|
||||
t.plan(2)
|
||||
const serverConfig = {}
|
||||
const opts = {
|
||||
schema: {
|
||||
querystring: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
opts.schema = normalizeSchema(opts.schema, serverConfig)
|
||||
validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))
|
||||
t.assert.ok(typeof opts[symbols.querystringSchema].schema.type === 'string')
|
||||
t.assert.strictEqual(typeof opts[symbols.querystringSchema], 'function')
|
||||
})
|
||||
|
||||
test('build schema - must throw if querystring and query schema exist', t => {
|
||||
t.plan(2)
|
||||
try {
|
||||
const serverConfig = {}
|
||||
const opts = {
|
||||
schema: {
|
||||
query: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
},
|
||||
querystring: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
opts.schema = normalizeSchema(opts.schema, serverConfig)
|
||||
} catch (err) {
|
||||
t.assert.strictEqual(err.code, 'FST_ERR_SCH_DUPLICATE')
|
||||
t.assert.strictEqual(err.message, 'Schema with \'querystring\' already present!')
|
||||
}
|
||||
})
|
||||
|
||||
test('build schema - params schema', t => {
|
||||
t.plan(1)
|
||||
const opts = {
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))
|
||||
t.assert.strictEqual(typeof opts[symbols.paramsSchema], 'function')
|
||||
})
|
||||
|
||||
test('build schema - headers schema', t => {
|
||||
t.plan(1)
|
||||
const opts = {
|
||||
schema: {
|
||||
headers: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'content-type': { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))
|
||||
t.assert.strictEqual(typeof opts[symbols.headersSchema], 'function')
|
||||
})
|
||||
|
||||
test('build schema - headers are lowercase', t => {
|
||||
t.plan(1)
|
||||
const opts = {
|
||||
schema: {
|
||||
headers: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'Content-Type': { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => {
|
||||
t.assert.ok(schema.properties['content-type'], 'lowercase content-type exists')
|
||||
return () => { }
|
||||
})
|
||||
})
|
||||
|
||||
test('build schema - headers are not lowercased in case of custom object', t => {
|
||||
t.plan(1)
|
||||
|
||||
class Headers { }
|
||||
const opts = {
|
||||
schema: {
|
||||
headers: new Headers()
|
||||
}
|
||||
}
|
||||
validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => {
|
||||
t.assert.ok(schema, Headers)
|
||||
return () => { }
|
||||
})
|
||||
})
|
||||
|
||||
test('build schema - headers are not lowercased in case of custom validator provided', t => {
|
||||
t.plan(1)
|
||||
|
||||
class Headers { }
|
||||
const opts = {
|
||||
schema: {
|
||||
headers: new Headers()
|
||||
}
|
||||
}
|
||||
validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => {
|
||||
t.assert.ok(schema, Headers)
|
||||
return () => { }
|
||||
}, true)
|
||||
})
|
||||
|
||||
test('build schema - uppercased headers are not included', t => {
|
||||
t.plan(1)
|
||||
const opts = {
|
||||
schema: {
|
||||
headers: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'Content-Type': { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => {
|
||||
t.assert.ok(!('Content-Type' in schema.properties), 'uppercase does not exist')
|
||||
return () => { }
|
||||
})
|
||||
})
|
||||
|
||||
test('build schema - mixed schema types are individually skipped or normalized', t => {
|
||||
t.plan(2)
|
||||
|
||||
class CustomSchemaClass { }
|
||||
|
||||
const testCases = [{
|
||||
schema: {
|
||||
body: new CustomSchemaClass()
|
||||
},
|
||||
assertions: (schema) => {
|
||||
t.assert.ok(schema.body, CustomSchemaClass)
|
||||
}
|
||||
}, {
|
||||
schema: {
|
||||
response: {
|
||||
200: new CustomSchemaClass()
|
||||
}
|
||||
},
|
||||
assertions: (schema) => {
|
||||
t.assert.ok(schema.response[200], CustomSchemaClass)
|
||||
}
|
||||
}]
|
||||
|
||||
testCases.forEach((testCase) => {
|
||||
const result = normalizeSchema(testCase.schema, {})
|
||||
testCase.assertions(result)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user