UNPKG

server

Version:

A modern and powerful server for Node.js

176 lines (142 loc) 4.64 kB
const join = require('../join'); const modern = require('./index'); const middle = (req, res, next) => next(); const ctx = { req: {}, res: {} }; describe('initializes', () => { it('returns a function', () => { expect(typeof modern(middle)).toBe('function'); }); it('the returned modern middleware has 1 arg', () => { expect(modern(middle).length).toBe(1); }); it('requires an argument', () => { expect(() => modern()).toThrow(); }); it('a non-function argument throws', () => { expect(() => modern(true)).toThrow(); expect(() => modern(5)).toThrow(); expect(() => modern('')).toThrow(); expect(() => modern([])).toThrow(); expect(() => modern({})).toThrow(); expect(() => modern(() => {})).not.toThrow(); }); }); describe('call the middleware', () => { it('returns a promise when called', () => { expect(modern(middle)(ctx) instanceof Promise).toBe(true); }); it('requires the context to be called', async () => { expect(modern(middle)()).rejects.toBeDefined(); }); it('rejected with empty context', async () => { expect(modern(middle)({})).rejects.toBeDefined(); }); it('rejected without res', async () => { expect(modern(middle)({ req: {} })).rejects.toBeDefined(); }); it('rejected without req', async () => { expect(modern(middle)({ res: {} })).rejects.toBeDefined(); }); }); describe('Middleware handles the promise', () => { it('resolves when next is called empty', async () => { await modern((req, res, next) => next())(ctx); }); it('cannot handle error middleware', async () => { // eslint-disable-next-line no-unused-vars expect(() => modern((err, req, res, next) => {})).toThrow(); }); it('keeps the context', async () => { const ctx = { req: 1, res: 2 }; await modern((req, res, next) => next())(ctx); expect(ctx.req).toBe(1); expect(ctx.res).toBe(2); }); it('can modify the context', async () => { const middle = (req, res, next) => { req.user = 'myname'; res.send = 'sending'; next(); }; const ctx = { req: {}, res: {} }; await modern(middle)(ctx); expect(ctx.req.user).toBe('myname'); expect(ctx.res.send).toBe('sending'); }); it('has chainable context', async () => { const ctx = { req: { user: 'a' }, res: { send: 'b' } }; const middle = (req, res, next) => { req.user += 1; res.send += 2; next(); }; await modern(middle)(ctx).then(() => modern(middle)(ctx)); expect(ctx.req.user).toBe('a11'); expect(ctx.res.send).toBe('b22'); }); it('factory can receive options', async () => { // The full context const ctx = { req: { user: 'a' }, res: { send: 'b' }, options: { extra: 1} }; // A middleware factory const factory = opts => { return (req, res, next) => { req.user += opts.extra; res.send += opts.extra; next(); }; }; // Plain ol' middleware const factored = factory({ extra: 1 }); // We need to pass it and then re-call it const middles = [ // Native sync, this could be extracted to '({ req, res, options })' ctx => { ctx.req.user += ctx.options.extra; ctx.res.send += ctx.options.extra; }, // Native async ctx => new Promise((resolve) => { ctx.req.user += ctx.options.extra; ctx.res.send += ctx.options.extra; resolve(); }), // Hardcoded case: modern((req, res, next) => { req.user += 1; res.send += 1; next(); }), // Using some info from the context: ctx => modern((req, res, next) => { req.user += ctx.options.extra; res.send += ctx.options.extra; next(); })(ctx), // The definition might come from a factory ctx => modern(factory({ extra: ctx.options.extra }))(ctx), // The same as above but already defined ctx => modern(factored)(ctx) ]; await join(middles)(ctx); expect(ctx.req.user).toBe('a111111'); expect(ctx.res.send).toBe('b111111'); }); it('rejects when next is called with an error', async () => { const wrong = (req, res, next) => next(new Error('Custom error')); expect(modern(wrong)(ctx)).rejects.toBeDefined(); }); it('does not resolve nor reject if next is not called', async () => { modern(() => {})(ctx).then(() => { expect('It was resolved').toBe(false); }).catch(() => { expect('It was rejected').toBe(false); }); return new Promise(resolve => { setTimeout(() => resolve(), 1000); }); }); });