deno.land / x / hooks@v0.6.5 / test / function.test.ts
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433import * as assert from 'assert';import { hooks, middleware, getManager, HookContext, BaseHookContext, NextFunction, setMiddleware, functionHooks} from '../src';
describe('functionHooks', () => { const hello = async (name?: string, _params: any = {}) => { return `Hello ${name}`; };
it('returns a new function, registers hooks', () => { const fn = hooks(hello, []);
assert.notDeepEqual(fn, hello); assert.notStrictEqual(getManager(fn), null); });
it('returns a new function, without hooks', () => { const fn = hooks(hello);
assert.notDeepEqual(fn, hello); assert.ok(getManager(fn) !== null); });
it('conserve name and length properties', () => { const fn = hooks(hello, []);
assert.strictEqual(fn.length, hello.length); assert.strictEqual(fn.name, hello.name); });
it('throws an error with non function', () => { assert.throws(() => functionHooks({}, middleware([]))); })
it('can override arguments, has context', async () => { const addYou = async (ctx: HookContext, next: NextFunction) => { assert.ok(ctx instanceof BaseHookContext); assert.deepStrictEqual(ctx.arguments, [ 'There' ]); ctx.arguments[0] += ' You';
await next(); };
const fn = hooks(hello, middleware([ addYou ])); const res = await fn('There');
assert.strictEqual(res, 'Hello There You'); });
it('has fn.original', async () => { const fn = hooks(hello, middleware([ async (ctx: HookContext, next: NextFunction) => { ctx.arguments[0] += ' You';
await next(); } ]));
assert.strictEqual(typeof fn.original, 'function');
assert.strictEqual(await fn.original('Dave'), 'Hello Dave'); });
it('can override context.result before, skips method call', async () => { const hello = async (_name: string) => { throw new Error('Should never get here'); }; const updateResult = async (ctx: HookContext, next: NextFunction) => { ctx.result = 'Hello Dave';
await next(); };
const fn = hooks(hello, middleware([ updateResult ])); const res = await fn('There');
assert.strictEqual(res, 'Hello Dave'); });
it('can set context.result to undefined, skips method call, returns undefined', async () => { const hello = async (_name: string) => { throw new Error('Should never get here'); }; const updateResult = async (ctx: HookContext, next: NextFunction) => { ctx.result = undefined;
await next(); };
const fn = hooks(hello, middleware([ updateResult ])); const res = await fn('There');
assert.strictEqual(res, undefined); });
it('deleting context.result, does not skip method call', async () => { const hello = async (name: string) => { return name; }; const updateResult = async (ctx: HookContext, next: NextFunction) => { ctx.result = 'Dave';
await next(); }; const deleteResult = async (ctx: HookContext, next: NextFunction) => { delete ctx.result;
await next(); };
const fn = hooks(hello, middleware([ updateResult, deleteResult ])); const res = await fn('There');
assert.strictEqual(res, 'There'); });
it('can override context.result after', async () => { const updateResult = async (ctx: HookContext, next: NextFunction) => { await next();
ctx.result += ' You!'; };
const fn = hooks(hello, middleware([ updateResult ])); const res = await fn('There');
assert.strictEqual(res, 'Hello There You!'); });
it('maintains the function context and sets context.self', async () => { const hook = async function (this: any, context: HookContext, next: NextFunction) { assert.strictEqual(obj, this); assert.strictEqual(context.self, obj); await next(); }; const obj: any = { message: 'Hi',
sayHi: hooks(async function (this: any, name: string) { return `${this.message} ${name}`; }, middleware([ hook ])) }; const res = await obj.sayHi('Dave');
assert.strictEqual(res, 'Hi Dave'); });
it('uses hooks from context object and its prototypes', async () => { const o1 = { message: 'Hi' }; const o2 = Object.create(o1);
setMiddleware(o1, [async (ctx: HookContext, next: NextFunction) => { ctx.arguments[0] += ' o1';
await next(); }]);
setMiddleware(o2, [async (ctx, next) => { ctx.arguments[0] += ' o2';
await next(); }]);
o2.sayHi = hooks(async function (this: any, name: string) { return `${this.message} ${name}`; }, middleware([async (ctx, next) => { ctx.arguments[0] += ' fn';
await next(); }]));
const res = await o2.sayHi('Dave');
assert.strictEqual(res, 'Hi Dave o1 o2 fn'); });
it('wraps an existing hooked function properly', async () => { const one = async (ctx: HookContext, next: NextFunction) => { await next();
ctx.result += ' One'; }; const two = async (ctx: HookContext, next: NextFunction) => { await next();
ctx.result += ' Two'; }; const three = async (ctx: HookContext, next: NextFunction) => { await next();
ctx.result += ' Three'; }; const first = hooks(hello, middleware([ one, two ])); const second = hooks(first, middleware([ three ])); const mngr = getManager(second);
if (mngr === null) { assert.ok(false, 'There should be a manager'); } else { assert.deepEqual(mngr.getMiddleware(), [ one, two, three ]); }
const result = await second('Dave');
assert.strictEqual(result, 'Hello Dave Three Two One'); });
it('chains context and default initializers', async () => { const first = hooks(hello, middleware([], { params: [ 'name' ], defaults () { return { defaulting: true }; } })); const second = hooks(first, middleware([ async (ctx, next) => { assert.ok(ctx.defaulting); ctx.name += ctx.testing; await next(); } ]).props({ testing: ' test value' }));
const result = await second('Dave');
assert.strictEqual(result, 'Hello Dave test value'); });
it('creates context with params and converts to arguments', async () => { const fn = hooks(hello, middleware([ async (ctx, next) => { assert.strictEqual(ctx.name, 'Dave');
ctx.name = 'Changed';
await next(); } ]).params('name'));
assert.strictEqual(await fn('Dave'), 'Hello Changed'); });
it('assigns props to context', async () => { const fn = hooks(hello, middleware([ async (ctx, next) => { assert.strictEqual(ctx.name, 'Dave'); assert.strictEqual(ctx.dev, true);
ctx.name = 'Changed';
await next(); } ]).params('name').props({ dev: true }));
assert.strictEqual(await fn('Dave'), 'Hello Changed'); });
it('assigns props to context by options', async () => { const fn = hooks(hello, middleware([ async (ctx, next) => { assert.strictEqual(ctx.name, 'Dave'); assert.strictEqual(ctx.dev, true);
ctx.name = 'Changed';
await next(); } ], { params: ['name'], props: { dev: true } }));
assert.strictEqual(await fn('Dave'), 'Hello Changed'); });
it('ctx.arguments is configurable with named params', async () => { const modifyArgs = async (ctx: HookContext, next: NextFunction) => { ctx.arguments[0] = 'Changed'; ctx.arguments.push('no');
assert.strictEqual(ctx.name, ctx.arguments[0]);
await next(); };
const fn = hooks(hello, middleware([ modifyArgs ]).params('name'));
const customContext = fn.createContext(); const resultContext = await fn('Daffl', {}, customContext);
assert.strictEqual(resultContext, customContext); assert.deepEqual(resultContext, fn.createContext({ arguments: ['Changed', {}, 'no'], name: 'Changed', result: 'Hello Changed' })); });
it('can take and return an existing HookContext', async () => { const message = 'Custom message'; const fn = hooks(hello, middleware([ async (ctx, next) => { assert.strictEqual(ctx.name, 'Dave'); assert.strictEqual(ctx.message, message);
ctx.name = 'Changed'; await next(); } ]).params('name'));
const customContext = fn.createContext({ message }); const resultContext: HookContext = await fn('Dave', {}, customContext);
assert.strictEqual(resultContext, customContext); assert.deepEqual(resultContext, fn.createContext({ arguments: ['Changed', {}], message: 'Custom message', name: 'Changed', result: 'Hello Changed' })); });
it('calls middleware one time', async () => { let called = 0;
const sayHi = hooks((name: any) => `Hi ${name}`, middleware([ async (_context, next) => { called++; await next(); } ]));
const exclamation = hooks(sayHi, middleware([ async (context, next) => { await next(); context.result += '!'; } ]));
const result = await exclamation('Bertho');
assert.strictEqual(result, 'Hi Bertho!'); assert.strictEqual(called, 1); });
it('conserves method properties', async () => { const TEST = Symbol('test'); const hello = (name: any) => `Hi ${name}`; (hello as any)[TEST] = true;
const sayHi = hooks(hello, middleware([ async (context, next) => { await next(); context.result += '!'; } ]));
const result = await sayHi('Bertho');
assert.strictEqual(result, 'Hi Bertho!'); assert.strictEqual((sayHi as any)[TEST], (hello as any)[TEST]); });
it('works with array as middleware', async () => { const TEST = Symbol('test'); const hello = (name: any) => `Hi ${name}`; (hello as any)[TEST] = true;
const sayHi = hooks(hello, [ async (context, next) => { await next(); context.result += '!'; } ]);
const result = await sayHi('Bertho');
assert.strictEqual(result, 'Hi Bertho!'); assert.strictEqual((sayHi as any)[TEST], (hello as any)[TEST]); });
it('context has own properties', async () => { const fn = hooks(hello, middleware([]).params('name'));
const customContext = fn.createContext({ message: 'Hi !' }); const resultContext: HookContext = await fn('Dave', {}, customContext); const keys = Object.keys(resultContext);
assert.ok(keys.includes('self')); assert.ok(keys.includes('message')); assert.ok(keys.includes('name')); assert.ok(keys.includes('arguments')); assert.ok(keys.includes('result')); });
it('same params and props throw an error', async () => { const hello = async (name?: string) => { return `Hello ${name}`; }; assert.throws(() => hooks(hello, middleware([]).params('name').props({ name: 'David' })), { message: `Hooks can not have a property and param named 'name'. Use .defaults instead.` }); });
it('creates context with default params', async () => { const fn = hooks(hello, middleware([ async (ctx, next) => { assert.deepEqual(ctx.params, {});
await next(); }]).params('name', 'params').defaults(() => { return { name: 'Bertho', params: {} } }) );
assert.strictEqual(await fn('Dave'), 'Hello Dave'); assert.strictEqual(await fn(), 'Hello Bertho'); });});
Version Info