fatsify核心功能示例测试!!!

This commit is contained in:
2025-09-21 14:50:41 +08:00
commit 9145aea047
1958 changed files with 230098 additions and 0 deletions

38
node_modules/fastify/test/internals/all.test.js generated vendored Normal file
View 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 })
}
})

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

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

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

View 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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

506
node_modules/fastify/test/internals/request.test.js generated vendored Normal file
View 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
View 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
View 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)
})
})