UNPKG

@fastify/middie

Version:

Middleware engine for Fastify

789 lines (632 loc) 15.4 kB
'use strict' const { test } = require('tap') const Fastify = require('fastify') const sget = require('simple-get').concat const cors = require('cors') const middiePlugin = require('../index') const { FST_ERR_MIDDIE_INVALID_HOOK } = require('../lib/errors') test('Should support connect style middlewares', t => { t.plan(4) const fastify = Fastify() t.teardown(fastify.close) fastify .register(middiePlugin) .after(() => { fastify.use(cors()) }) fastify.get('/', async () => { return { hello: 'world' } }) fastify.listen({ port: 0 }, (err, address) => { t.error(err) sget({ method: 'GET', url: address }, (err, res, data) => { t.error(err) t.match(res.headers, { 'access-control-allow-origin': '*' }) t.same(JSON.parse(data), { hello: 'world' }) }) }) }) test('Should support connect style middlewares (async await)', async t => { t.plan(3) const fastify = Fastify() t.teardown(fastify.close) await fastify.register(middiePlugin) fastify.use(cors()) fastify.get('/', async () => { return { hello: 'world' } }) const address = await fastify.listen({ port: 0 }) return new Promise((resolve) => { sget({ method: 'GET', url: address }, (err, res, data) => { t.error(err) t.match(res.headers, { 'access-control-allow-origin': '*' }) t.same(JSON.parse(data), { hello: 'world' }) resolve() }) }) }) test('Should support connect style middlewares (async await after)', async t => { t.plan(3) const fastify = Fastify() t.teardown(fastify.close) fastify.register(middiePlugin) await fastify.after() fastify.use(cors()) fastify.get('/', async () => { return { hello: 'world' } }) const address = await fastify.listen({ port: 0 }) return new Promise((resolve) => { sget({ method: 'GET', url: address }, (err, res, data) => { t.error(err) t.match(res.headers, { 'access-control-allow-origin': '*' }) t.same(JSON.parse(data), { hello: 'world' }) resolve() }) }) }) test('Should support per path middlewares', t => { t.plan(5) const fastify = Fastify() t.teardown(fastify.close) fastify .register(middiePlugin) .after(() => { fastify.use('/cors', cors()) }) fastify.get('/cors/hello', async () => { return { hello: 'world' } }) fastify.get('/', async () => { return { hello: 'world' } }) fastify.listen({ port: 0 }, (err, address) => { t.error(err) sget({ method: 'GET', url: address + '/cors/hello' }, (err, res) => { t.error(err) t.match(res.headers, { 'access-control-allow-origin': '*' }) }) sget({ method: 'GET', url: address }, (err, res) => { t.error(err) t.notOk(res.headers['access-control-allow-origin']) }) }) }) test('Encapsulation support / 1', t => { t.plan(2) const fastify = Fastify() fastify.register((instance, _opts, next) => { instance.register(middiePlugin) .after(() => { instance.use(middleware) }) instance.get('/plugin', (_req, reply) => { reply.send('ok') }) next() }) fastify.get('/', (_req, reply) => { reply.send('ok') }) fastify.listen({ port: 0 }, (err, address) => { t.error(err) sget({ method: 'GET', url: address }, (err) => { t.error(err) fastify.close() }) }) function middleware () { t.fail('Shuld not be called') } }) test('Encapsulation support / 2', t => { t.plan(2) const fastify = Fastify() fastify.register(middiePlugin) fastify.register((instance, _opts, next) => { instance.use(middleware) instance.get('/plugin', (_req, reply) => { reply.send('ok') }) next() }) fastify.get('/', (_req, reply) => { reply.send('ok') }) fastify.listen({ port: 0 }, (err, address) => { t.error(err) sget({ method: 'GET', url: address }, (err) => { t.error(err) fastify.close() }) }) function middleware () { t.fail('Shuld not be called') } }) test('Encapsulation support / 3', t => { t.plan(5) const fastify = Fastify() t.teardown(fastify.close) fastify.register(middiePlugin) fastify.register((instance, _opts, next) => { instance.use(cors()) instance.get('/plugin', (_req, reply) => { reply.send('ok') }) next() }) fastify.get('/', (_req, reply) => { reply.send('ok') }) fastify.listen({ port: 0 }, (err, address) => { t.error(err) sget({ method: 'GET', url: address + '/plugin' }, (err, res) => { t.error(err) t.match(res.headers, { 'access-control-allow-origin': '*' }) }) sget({ method: 'GET', url: address }, (err, res) => { t.error(err) t.notMatch(res.headers, { 'access-control-allow-origin': '*' }) }) }) }) test('Encapsulation support / 4', t => { t.plan(5) const fastify = Fastify() t.teardown(fastify.close) fastify.register(middiePlugin) fastify.after(() => { fastify.use(middleware1) }) fastify.register((instance, _opts, next) => { instance.use(middleware2) instance.get('/plugin', (_req, reply) => { reply.send('ok') }) next() }) fastify.get('/', (_req, reply) => { reply.send('ok') }) fastify.listen({ port: 0 }, (err, address) => { t.error(err) sget({ method: 'GET', url: address + '/plugin' }, (err, res) => { t.error(err) t.match(res.headers, { 'x-middleware-1': 'true', 'x-middleware-2': 'true' }) }) sget({ method: 'GET', url: address }, (err, res) => { t.error(err) t.match(res.headers, { 'x-middleware-1': 'true' }) }) }) function middleware1 (_req, res, next) { res.setHeader('x-middleware-1', true) next() } function middleware2 (_req, res, next) { res.setHeader('x-middleware-2', true) next() } }) test('Encapsulation support / 5', t => { t.plan(7) const fastify = Fastify() t.teardown(fastify.close) fastify.register(middiePlugin) fastify.after(() => { fastify.use(middleware1) }) fastify.register((instance, _opts, next) => { instance.use(middleware2) instance.get('/', (_req, reply) => { reply.send('ok') }) instance.register((i, _opts, next) => { i.use(middleware3) i.get('/nested', (_req, reply) => { reply.send('ok') }) next() }) next() }, { prefix: '/plugin' }) fastify.get('/', (_req, reply) => { reply.send('ok') }) fastify.listen({ port: 0 }, (err, address) => { t.error(err) sget({ method: 'GET', url: address + '/plugin/nested' }, (err, res) => { t.error(err) t.match(res.headers, { 'x-middleware-1': 'true', 'x-middleware-2': 'true', 'x-middleware-3': 'true' }) }) sget({ method: 'GET', url: address + '/plugin' }, (err, res) => { t.error(err) t.match(res.headers, { 'x-middleware-1': 'true', 'x-middleware-2': 'true' }) }) sget({ method: 'GET', url: address }, (err, res) => { t.error(err) t.match(res.headers, { 'x-middleware-1': 'true' }) }) }) function middleware1 (_req, res, next) { res.setHeader('x-middleware-1', true) next() } function middleware2 (_req, res, next) { res.setHeader('x-middleware-2', true) next() } function middleware3 (_req, res, next) { res.setHeader('x-middleware-3', true) next() } }) test('Middleware chain', t => { t.plan(5) const order = [1, 2, 3] const fastify = Fastify() fastify .register(middiePlugin) .after(() => { fastify .use(middleware1) .use(middleware2) .use(middleware3) }) fastify.get('/', async () => { return { hello: 'world' } }) fastify.listen({ port: 0 }, (err, address) => { t.error(err) sget({ method: 'GET', url: address }, (err) => { t.error(err) fastify.close() }) }) function middleware1 (_req, _res, next) { t.equal(order.shift(), 1) next() } function middleware2 (_req, _res, next) { t.equal(order.shift(), 2) next() } function middleware3 (_req, _res, next) { t.equal(order.shift(), 3) next() } }) test('Middleware chain (with errors) / 1', t => { t.plan(3) const fastify = Fastify() fastify .register(middiePlugin) .after(() => { fastify .use(middleware1) .use(middleware2) .use(middleware3) }) fastify.get('/', async () => { return { hello: 'world' } }) fastify.listen({ port: 0 }, (err, address) => { t.error(err) sget({ method: 'GET', url: address }, (err, res, _data) => { t.error(err) t.equal(res.statusCode, 500) fastify.close() }) }) function middleware1 (_req, _res, next) { next(new Error('middleware1')) } function middleware2 () { t.fail('this should not be executed') } function middleware3 () { t.fail('this should not be executed') } }) test('Middleware chain (with errors) / 2', t => { t.plan(5) const fastify = Fastify() fastify.setErrorHandler((err, _req, reply) => { t.equal(err.message, 'middleware2') reply.send(err) }) fastify .register(middiePlugin) .after(() => { fastify .use(middleware1) .use(middleware2) .use(middleware3) }) fastify.get('/', async () => { return { hello: 'world' } }) fastify.listen({ port: 0 }, (err, address) => { t.error(err) sget({ method: 'GET', url: address }, (err, res, _data) => { t.error(err) t.equal(res.statusCode, 500) fastify.close() }) }) function middleware1 (_req, _res, next) { t.pass('called') next() } function middleware2 (_req, _res, next) { next(new Error('middleware2')) } function middleware3 () { t.fail('We should not be here') } }) test('Send a response from a middleware', t => { t.plan(4) const fastify = Fastify() fastify .register(middiePlugin) .after(() => { fastify .use(middleware1) .use(middleware2) }) fastify.addHook('preValidation', () => { t.fail('We should not be here') }) fastify.addHook('preParsing', () => { t.fail('We should not be here') }) fastify.addHook('preHandler', () => { t.fail('We should not be here') }) fastify.addHook('onSend', () => { t.fail('We should not be here') }) fastify.addHook('onResponse', (_req, _reply, next) => { t.ok('called') next() }) fastify.get('/', () => { t.fail('We should not be here') }) fastify.listen({ port: 0 }, (err, address) => { t.error(err) sget({ method: 'GET', url: address, json: true }, (err, _res, data) => { t.error(err) t.same(data, { hello: 'world' }) fastify.close() }) }) function middleware1 (_req, res, _next) { res.end(JSON.stringify({ hello: 'world' })) } function middleware2 (_req, _res, _next) { t.fail('We should not be here') } }) test('Should support plugin level prefix', t => { t.plan(4) const fastify = Fastify() t.teardown(fastify.close) fastify.register(middiePlugin) fastify.register((instance, _opts, next) => { instance.use('/world', (_req, res, next) => { res.setHeader('x-foo', 'bar') next() }) instance.get('/world', (_req, reply) => { reply.send({ hello: 'world' }) }) next() }, { prefix: '/hello' }) fastify.listen({ port: 0 }, (err, address) => { t.error(err) sget({ method: 'GET', url: address + '/hello/world' }, (err, res, data) => { t.error(err) t.equal(res.headers['x-foo'], 'bar') t.same(JSON.parse(data), { hello: 'world' }) }) }) }) test('register the middleware at preHandler hook', async t => { t.plan(2) const fastify = Fastify() t.teardown(fastify.close) let onRequestCalled = false await fastify.register(middiePlugin, { hook: 'preHandler' }) fastify.use(function (_req, _res, next) { t.ok(onRequestCalled) next() }) fastify.addHook('onRequest', function (_req, _reply, next) { onRequestCalled = true next() }) fastify.get('/', async () => { return { hello: 'world' } }) const res = await fastify.inject('/') t.same(res.json(), { hello: 'world' }) }) test('register the middleware at preParsing hook', async t => { t.plan(2) const fastify = Fastify() t.teardown(fastify.close) let onRequestCalled = false await fastify.register(middiePlugin, { hook: 'preParsing' }) fastify.use(function (_req, _res, next) { t.ok(onRequestCalled) next() }) fastify.addHook('onRequest', function (_req, _reply, next) { onRequestCalled = true next() }) fastify.get('/', async () => { return { hello: 'world' } }) const res = await fastify.inject('/') t.same(res.json(), { hello: 'world' }) }) test('register the middleware at preValidation hook', async t => { t.plan(2) const fastify = Fastify() t.teardown(fastify.close) let onRequestCalled = false await fastify.register(middiePlugin, { hook: 'preValidation' }) fastify.use(function (_req, _res, next) { t.ok(onRequestCalled) next() }) fastify.addHook('onRequest', function (_req, _reply, next) { onRequestCalled = true next() }) fastify.get('/', async () => { return { hello: 'world' } }) const res = await fastify.inject('/') t.same(res.json(), { hello: 'world' }) }) test('register the middleware at preSerialization hook', async t => { t.plan(2) const fastify = Fastify() t.teardown(fastify.close) let onRequestCalled = false await fastify.register(middiePlugin, { hook: 'preSerialization' }) fastify.use(function (_req, _res, next) { t.ok(onRequestCalled) next() }) fastify.addHook('onRequest', function (_req, _reply, next) { onRequestCalled = true next() }) fastify.get('/', async () => { return { hello: 'world' } }) const res = await fastify.inject('/') t.same(res.json(), { hello: 'world' }) }) test('register the middleware at onSend hook', async t => { t.plan(2) const fastify = Fastify() t.teardown(fastify.close) let onRequestCalled = false await fastify.register(middiePlugin, { hook: 'onSend' }) fastify.use(function (_req, _res, next) { t.ok(onRequestCalled) next() }) fastify.addHook('onRequest', function (_req, _reply, next) { onRequestCalled = true next() }) fastify.get('/', async () => { return { hello: 'world' } }) const res = await fastify.inject('/') t.same(res.json(), { hello: 'world' }) }) test('throw error when registering middie at onRequestAborted hook', async t => { const fastify = Fastify() t.teardown(fastify.close) t.rejects(async () => fastify.register(middiePlugin, { hook: 'onRequestAborted' }), new FST_ERR_MIDDIE_INVALID_HOOK('onRequestAborted') ) })