You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

479 lines
9.4 KiB

'use strict'
const t = require('tap')
const test = t.test
const Fastify = require('..')
const sget = require('simple-get').concat
const http = require('http')
const split = require('split2')
test('Should register a versioned route', t => {
t.plan(11)
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
version: '1.2.0',
handler: (req, reply) => {
reply.send({ hello: 'world' })
}
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': '1.x'
}
}, (err, res) => {
t.error(err)
t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
t.strictEqual(res.statusCode, 200)
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': '1.2.x'
}
}, (err, res) => {
t.error(err)
t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
t.strictEqual(res.statusCode, 200)
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': '1.2.0'
}
}, (err, res) => {
t.error(err)
t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
t.strictEqual(res.statusCode, 200)
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': '1.2.1'
}
}, (err, res) => {
t.error(err)
t.strictEqual(res.statusCode, 404)
})
})
test('Should register the same route with different versions', t => {
t.plan(8)
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
version: '1.2.0',
handler: (req, reply) => {
reply.send('1.2.0')
}
})
fastify.route({
method: 'GET',
url: '/',
version: '1.3.0',
handler: (req, reply) => {
reply.send('1.3.0')
}
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': '1.x'
}
}, (err, res) => {
t.error(err)
t.strictEqual(res.statusCode, 200)
t.strictEqual(res.payload, '1.3.0')
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': '1.2.x'
}
}, (err, res) => {
t.error(err)
t.strictEqual(res.statusCode, 200)
t.strictEqual(res.payload, '1.2.0')
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': '2.x'
}
}, (err, res) => {
t.error(err)
t.strictEqual(res.statusCode, 404)
})
})
test('The versioned route should take precedence', t => {
t.plan(3)
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
handler: (req, reply) => {
reply.send({ winter: 'is coming' })
}
})
fastify.route({
method: 'GET',
url: '/',
version: '1.2.0',
handler: (req, reply) => {
reply.send({ hello: 'world' })
}
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': '1.x'
}
}, (err, res) => {
t.error(err)
t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
t.strictEqual(res.statusCode, 200)
})
})
test('Versioned route but not version header should return a 404', t => {
t.plan(2)
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
version: '1.2.0',
handler: (req, reply) => {
reply.send({ hello: 'world' })
}
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.error(err)
t.strictEqual(res.statusCode, 404)
})
})
test('Should register a versioned route', t => {
t.plan(6)
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
version: '1.2.0',
handler: (req, reply) => {
reply.send({ hello: 'world' })
}
})
fastify.listen(0, err => {
t.error(err)
fastify.server.unref()
sget({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port,
headers: {
'Accept-Version': '1.x'
}
}, (err, response, body) => {
t.error(err)
t.strictEqual(response.statusCode, 200)
t.deepEqual(JSON.parse(body), { hello: 'world' })
})
sget({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port,
headers: {
'Accept-Version': '2.x'
}
}, (err, response, body) => {
t.error(err)
t.strictEqual(response.statusCode, 404)
})
})
})
test('Shorthand route declaration', t => {
t.plan(5)
const fastify = Fastify()
fastify.get('/', { version: '1.2.0' }, (req, reply) => {
reply.send({ hello: 'world' })
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': '1.x'
}
}, (err, res) => {
t.error(err)
t.deepEqual(JSON.parse(res.payload), { hello: 'world' })
t.strictEqual(res.statusCode, 200)
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': '1.2.1'
}
}, (err, res) => {
t.error(err)
t.strictEqual(res.statusCode, 404)
})
})
test('The not found handler should not use the Accept-Version header', t => {
t.plan(4)
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
version: '1.2.0',
handler: (req, reply) => {
reply.send({ hello: 'world' })
}
})
fastify.setNotFoundHandler(function (req, reply) {
t.notOk(req.headers['accept-version'])
reply.code(404).send('not found handler')
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': '2.x'
}
}, (err, res) => {
t.error(err)
t.deepEqual(res.payload, 'not found handler')
t.strictEqual(res.statusCode, 404)
})
})
test('Bad accept version (inject)', t => {
t.plan(4)
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
version: '1.2.0',
handler: (req, reply) => {
reply.send({ hello: 'world' })
}
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': 'a.b.c'
}
}, (err, res) => {
t.error(err)
t.strictEqual(res.statusCode, 404)
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
'Accept-Version': 12
}
}, (err, res) => {
t.error(err)
t.strictEqual(res.statusCode, 404)
})
})
test('Bas accept version (server)', t => {
t.plan(5)
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
version: '1.2.0',
handler: (req, reply) => {
reply.send({ hello: 'world' })
}
})
fastify.listen(0, err => {
t.error(err)
fastify.server.unref()
sget({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port,
headers: {
'Accept-Version': 'a.b.c'
}
}, (err, response, body) => {
t.error(err)
t.strictEqual(response.statusCode, 404)
})
sget({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port,
headers: {
'Accept-Version': 12
}
}, (err, response, body) => {
t.error(err)
t.strictEqual(response.statusCode, 404)
})
})
})
test('test log stream', t => {
t.plan(3)
const stream = split(JSON.parse)
const fastify = Fastify({
logger: {
stream: stream,
level: 'info'
}
})
fastify.get('/', { version: '1.2.0' }, function (req, reply) {
reply.send(new Error('kaboom'))
})
fastify.listen(0, err => {
t.error(err)
fastify.server.unref()
http.get({
hostname: 'localhost',
port: fastify.server.address().port,
path: '/',
method: 'GET',
headers: {
'Accept-Version': '1.x'
}
})
stream.once('data', listenAtLogLine => {
stream.once('data', line => {
t.equal(line.req.version, '1.x')
stream.once('data', line => {
t.equal(line.req.version, '1.x')
})
})
})
})
})
test('Should register a versioned route with custome versioning strategy', t => {
t.plan(8)
const versioning = {
storage: function () {
let versions = {}
return {
get: (version) => { return versions[version] || null },
set: (version, store) => { versions[version] = store },
del: (version) => { delete versions[version] },
empty: () => { versions = {} }
}
},
deriveVersion: (req, ctx) => {
return req.headers.accept
}
}
const fastify = Fastify({ versioning })
fastify.route({
method: 'GET',
url: '/',
version: 'application/vnd.example.api+json;version=2',
handler: (req, reply) => {
reply.send({ hello: 'from route v2' })
}
})
fastify.route({
method: 'GET',
url: '/',
version: 'application/vnd.example.api+json;version=3',
handler: (req, reply) => {
reply.send({ hello: 'from route v3' })
}
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
Accept: 'application/vnd.example.api+json;version=2'
}
}, (err, res) => {
t.error(err)
t.deepEqual(JSON.parse(res.payload), { hello: 'from route v2' })
t.strictEqual(res.statusCode, 200)
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
Accept: 'application/vnd.example.api+json;version=3'
}
}, (err, res) => {
t.error(err)
t.deepEqual(JSON.parse(res.payload), { hello: 'from route v3' })
t.strictEqual(res.statusCode, 200)
})
fastify.inject({
method: 'GET',
url: '/',
headers: {
Accept: 'application/vnd.example.api+json;version=4'
}
}, (err, res) => {
t.error(err)
t.strictEqual(res.statusCode, 404)
})
})