| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- import {expect} from 'chai';
- import {format} from '@e22m4u/js-format';
- import {ROOT_PATH} from '../constants.js';
- import {Route, HttpMethod} from './route.js';
- import {ServiceContainer} from '@e22m4u/js-service';
- import {RequestContext} from '../request-context.js';
- import {HookRegistry, RouterHookType} from '../hooks/index.js';
- import {createRequestMock, createResponseMock} from '../utils/index.js';
- describe('Route', function () {
- describe('constructor', function () {
- it('should require the "routeDef" parameter to be an Object', function () {
- const throwable = v => () => new Route(v);
- const error = v =>
- format('Route definition must be an Object, but %s was given.', v);
- expect(throwable('str')).to.throw(error('"str"'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(0)).to.throw(error('0'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable(null)).to.throw(error('null'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable(undefined)).to.throw(error('undefined'));
- expect(throwable(() => undefined)).to.throw(error('Function'));
- throwable({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- handler: () => 'Ok',
- })();
- });
- it('should require the "method" option to be a non-empty String', function () {
- const throwable = v => () =>
- new Route({
- method: v,
- path: ROOT_PATH,
- handler: () => 'Ok',
- });
- const error = v =>
- format(
- 'Option "method" must be a non-empty String, but %s was given.',
- v,
- );
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(0)).to.throw(error('0'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable(null)).to.throw(error('null'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable(undefined)).to.throw(error('undefined'));
- expect(throwable(() => undefined)).to.throw(error('Function'));
- throwable(HttpMethod.GET)();
- });
- it('should require the "path" option to be a non-empty String', function () {
- const throwable = v => () =>
- new Route({
- method: HttpMethod.GET,
- path: v,
- handler: () => 'Ok',
- });
- const error = v =>
- format(
- 'Option "path" must be a non-empty String, but %s was given.',
- v,
- );
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(0)).to.throw(error('0'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable(undefined)).to.throw(error('undefined'));
- expect(throwable(null)).to.throw(error('null'));
- expect(throwable(() => undefined)).to.throw(error('Function'));
- throwable('str')();
- });
- it('should require the "handler" option to be a Function', function () {
- const throwable = v => () =>
- new Route({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- handler: v,
- });
- const error = v =>
- format('Option "handler" must be a Function, but %s was given.', v);
- expect(throwable('str')).to.throw(error('"str"'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(0)).to.throw(error('0'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable(null)).to.throw(error('null'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable(undefined)).to.throw(error('undefined'));
- throwable(() => undefined)();
- });
- it('should require the "preHandler" option to be a Function or an Array', function () {
- const throwable = v => () =>
- new Route({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- preHandler: v,
- handler: () => 'Ok',
- });
- const error = v =>
- format(
- 'Option "preHandler" must be a Function ' +
- 'or an Array, but %s was given.',
- v,
- );
- expect(throwable('str')).to.throw(error('"str"'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(0)).to.throw(error('0'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable(null)).to.throw(error('null'));
- throwable([])();
- throwable(() => undefined)();
- throwable(undefined)();
- });
- it('should require each element in the "preHandler" option to be a Function', function () {
- const throwable = v => () =>
- new Route({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- preHandler: [v],
- handler: () => 'Ok',
- });
- const error = v =>
- format('Route pre-handler must be a Function, but %s was given.', v);
- expect(throwable('str')).to.throw(error('"str"'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(0)).to.throw(error('0'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable(null)).to.throw(error('null'));
- expect(throwable(undefined)).to.throw(error('undefined'));
- throwable(() => undefined)();
- });
- it('should require the "postHandler" option to be a Function or an Array', function () {
- const throwable = v => () =>
- new Route({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- postHandler: v,
- handler: () => 'Ok',
- });
- const error = v =>
- format(
- 'Option "postHandler" must be a Function ' +
- 'or an Array, but %s was given.',
- v,
- );
- expect(throwable('str')).to.throw(error('"str"'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(0)).to.throw(error('0'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable(null)).to.throw(error('null'));
- throwable([])();
- throwable(() => undefined)();
- throwable(undefined)();
- });
- it('should require each element in the "postHandler" option to be a Function', function () {
- const throwable = v => () =>
- new Route({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- postHandler: [v],
- handler: () => 'Ok',
- });
- const error = v =>
- format('Route post-handler must be a Function, but %s was given.', v);
- expect(throwable('str')).to.throw(error('"str"'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(0)).to.throw(error('0'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable({})).to.throw(error('Object'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable(null)).to.throw(error('null'));
- expect(throwable(undefined)).to.throw(error('undefined'));
- throwable(() => undefined)();
- });
- it('should require the "meta" option to be a plain Object', function () {
- const throwable = v => () =>
- new Route({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- handler: () => 'Ok',
- meta: v,
- });
- const error = v =>
- format('Option "meta" must be an Object, but %s was given.', v);
- expect(throwable('str')).to.throw(error('"str"'));
- expect(throwable('')).to.throw(error('""'));
- expect(throwable(10)).to.throw(error('10'));
- expect(throwable(0)).to.throw(error('0'));
- expect(throwable(true)).to.throw(error('true'));
- expect(throwable(false)).to.throw(error('false'));
- expect(throwable([])).to.throw(error('Array'));
- expect(throwable(null)).to.throw(error('null'));
- expect(throwable(() => undefined)).to.throw(error('Function'));
- throwable({foo: 'bar'})();
- throwable({})();
- throwable(undefined)();
- });
- it('should clone a given definition in the current instance', function () {
- const definition = {
- method: HttpMethod.GET,
- path: ROOT_PATH,
- handler: () => 'Ok',
- };
- const route = new Route(definition);
- const res = route.getDefinition();
- expect(res).to.be.eql(definition);
- expect(res).to.be.not.eq(definition);
- });
- it('should convert the "method" option to upper case', function () {
- const definition = {
- method: 'get',
- path: ROOT_PATH,
- handler: () => 'Ok',
- };
- const route = new Route(definition);
- const res = route.getDefinition();
- expect(res.method).to.be.eq('GET');
- });
- it('should add a single pre-handler to the hook registry', function () {
- const preHandler = () => undefined;
- const definition = {
- method: 'get',
- path: ROOT_PATH,
- handler: () => 'Ok',
- preHandler,
- };
- const route = new Route(definition);
- const hookReg = route.getHookRegistry();
- const res = hookReg.hasHook(RouterHookType.PRE_HANDLER, preHandler);
- expect(res).to.be.true;
- });
- it('should add each pre-handler from the array to the hook registry', function () {
- const preHandler1 = () => undefined;
- const preHandler2 = () => undefined;
- const definition = {
- method: 'get',
- path: ROOT_PATH,
- handler: () => 'Ok',
- preHandler: [preHandler1, preHandler2],
- };
- const route = new Route(definition);
- const hookReg = route.getHookRegistry();
- const res1 = hookReg.hasHook(RouterHookType.PRE_HANDLER, preHandler1);
- const res2 = hookReg.hasHook(RouterHookType.PRE_HANDLER, preHandler2);
- expect(res1).to.be.true;
- expect(res2).to.be.true;
- });
- it('should add a single post-handler to the hook registry', function () {
- const postHandler = () => undefined;
- const definition = {
- method: 'get',
- path: ROOT_PATH,
- handler: () => 'Ok',
- postHandler,
- };
- const route = new Route(definition);
- const hookReg = route.getHookRegistry();
- const res = hookReg.hasHook(RouterHookType.POST_HANDLER, postHandler);
- expect(res).to.be.true;
- });
- it('should add each post-handlers from the array to the hook registry', function () {
- const postHandler1 = () => undefined;
- const postHandler2 = () => undefined;
- const definition = {
- method: 'get',
- path: ROOT_PATH,
- handler: () => 'Ok',
- postHandler: [postHandler1, postHandler2],
- };
- const route = new Route(definition);
- const hookReg = route.getHookRegistry();
- const res1 = hookReg.hasHook(RouterHookType.POST_HANDLER, postHandler1);
- const res2 = hookReg.hasHook(RouterHookType.POST_HANDLER, postHandler2);
- expect(res1).to.be.true;
- expect(res2).to.be.true;
- });
- });
- describe('getDefinition', function () {
- it('should return a clone of the original route definition', function () {
- const definition = {
- method: HttpMethod.GET,
- path: '/myPath',
- handler: () => 'Ok',
- };
- const route = new Route(definition);
- expect(route.getDefinition()).to.be.eql(definition);
- });
- });
- describe('getHookRegistry', function () {
- it('should return the same hook registry instance on subsequent calls', function () {
- const route = new Route({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- handler: () => 'Ok',
- });
- const res1 = route.getHookRegistry();
- const res2 = route.getHookRegistry();
- expect(res1).to.be.instanceOf(HookRegistry);
- expect(res2).to.be.eq(res1);
- });
- });
- describe('method', function () {
- it('should return a value of the "method" option', function () {
- const route = new Route({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- handler: () => 'Ok',
- });
- expect(route.method).to.be.eq(HttpMethod.GET);
- });
- });
- describe('path', function () {
- it('should return a value of the "path" option', function () {
- const value = 'myPath';
- const route = new Route({
- method: HttpMethod.GET,
- path: value,
- handler: () => 'Ok',
- });
- expect(route.path).to.be.eq(value);
- });
- });
- describe('meta', function () {
- it('should return a value of the "meta" option', function () {
- const value = {foo: 'bar'};
- const route = new Route({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- handler: () => 'Ok',
- meta: value,
- });
- expect(route.meta).to.be.eql(value);
- });
- it('should return an empty object if the "meta" option is not provided', function () {
- const route = new Route({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- handler: () => 'Ok',
- });
- expect(route.meta).to.be.eql({});
- });
- it('should return an empty object if the "meta" option is undefined', function () {
- const route = new Route({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- handler: () => 'Ok',
- meta: undefined,
- });
- expect(route.meta).to.be.eql({});
- });
- });
- describe('handler', function () {
- it('should return a value of the "handler" option', function () {
- const value = () => 'Ok';
- const route = new Route({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- handler: value,
- });
- expect(route.handler).to.be.eq(value);
- });
- });
- describe('handle', function () {
- it('should invoke the handler with the given RequestContext and return its result', function () {
- const route = new Route({
- method: HttpMethod.GET,
- path: ROOT_PATH,
- handler(ctx) {
- expect(ctx).to.be.instanceof(RequestContext);
- return 'OK';
- },
- });
- const req = createRequestMock();
- const res = createResponseMock();
- const cont = new ServiceContainer();
- const ctx = new RequestContext(cont, req, res, route);
- const result = route.handle(ctx);
- expect(result).to.be.eq('OK');
- });
- });
- });
|