route.spec.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. import {Route} from './route.js';
  2. import {expect} from './chai.js';
  3. import {HttpMethod} from './route.js';
  4. import {format} from '@e22m4u/js-format';
  5. import {HookType} from './hooks/index.js';
  6. import {createRequestMock} from './utils/index.js';
  7. import {createResponseMock} from './utils/index.js';
  8. import {RequestContext} from './request-context.js';
  9. import {ServiceContainer} from '@e22m4u/js-service';
  10. describe('Route', function () {
  11. describe('constructor', function () {
  12. it('requires the first parameter to be an Object', function () {
  13. const throwable = v => () => new Route(v);
  14. const error = v =>
  15. format(
  16. 'The first parameter of Route.controller ' +
  17. 'should be an Object, but %s given.',
  18. v,
  19. );
  20. expect(throwable('str')).to.throw(error('"str"'));
  21. expect(throwable('')).to.throw(error('""'));
  22. expect(throwable(10)).to.throw(error('10'));
  23. expect(throwable(0)).to.throw(error('0'));
  24. expect(throwable(true)).to.throw(error('true'));
  25. expect(throwable(false)).to.throw(error('false'));
  26. expect(throwable(null)).to.throw(error('null'));
  27. expect(throwable([])).to.throw(error('Array'));
  28. expect(throwable(undefined)).to.throw(error('undefined'));
  29. expect(throwable(() => undefined)).to.throw(error('Function'));
  30. throwable({
  31. method: HttpMethod.GET,
  32. path: '/',
  33. handler: () => undefined,
  34. })();
  35. });
  36. it('requires the option "method" to be a non-empty String', function () {
  37. const throwable = v => () =>
  38. new Route({
  39. method: v,
  40. path: '/',
  41. handler: () => undefined,
  42. });
  43. const error = v =>
  44. format(
  45. 'The option "method" of the Route should be ' +
  46. 'a non-empty String, but %s given.',
  47. v,
  48. );
  49. expect(throwable('')).to.throw(error('""'));
  50. expect(throwable(10)).to.throw(error('10'));
  51. expect(throwable(0)).to.throw(error('0'));
  52. expect(throwable(true)).to.throw(error('true'));
  53. expect(throwable(false)).to.throw(error('false'));
  54. expect(throwable(null)).to.throw(error('null'));
  55. expect(throwable({})).to.throw(error('Object'));
  56. expect(throwable([])).to.throw(error('Array'));
  57. expect(throwable(undefined)).to.throw(error('undefined'));
  58. expect(throwable(() => undefined)).to.throw(error('Function'));
  59. throwable(HttpMethod.GET)();
  60. });
  61. it('requires the option "path" to be a non-empty String', function () {
  62. const throwable = v => () =>
  63. new Route({
  64. method: HttpMethod.GET,
  65. path: v,
  66. handler: () => undefined,
  67. });
  68. const error = v =>
  69. format(
  70. 'The option "path" of the Route should be ' +
  71. 'a String, but %s given.',
  72. v,
  73. );
  74. expect(throwable(10)).to.throw(error('10'));
  75. expect(throwable(0)).to.throw(error('0'));
  76. expect(throwable(true)).to.throw(error('true'));
  77. expect(throwable(false)).to.throw(error('false'));
  78. expect(throwable(null)).to.throw(error('null'));
  79. expect(throwable({})).to.throw(error('Object'));
  80. expect(throwable([])).to.throw(error('Array'));
  81. expect(throwable(undefined)).to.throw(error('undefined'));
  82. expect(throwable(() => undefined)).to.throw(error('Function'));
  83. throwable('str')();
  84. throwable('')();
  85. });
  86. it('requires the option "handler" to be a non-empty String', function () {
  87. const throwable = v => () =>
  88. new Route({
  89. method: HttpMethod.GET,
  90. path: '/',
  91. handler: v,
  92. });
  93. const error = v =>
  94. format(
  95. 'The option "handler" of the Route should be ' +
  96. 'a Function, but %s given.',
  97. v,
  98. );
  99. expect(throwable('str')).to.throw(error('"str"'));
  100. expect(throwable('')).to.throw(error('""'));
  101. expect(throwable(10)).to.throw(error('10'));
  102. expect(throwable(0)).to.throw(error('0'));
  103. expect(throwable(true)).to.throw(error('true'));
  104. expect(throwable(false)).to.throw(error('false'));
  105. expect(throwable(null)).to.throw(error('null'));
  106. expect(throwable({})).to.throw(error('Object'));
  107. expect(throwable([])).to.throw(error('Array'));
  108. expect(throwable(undefined)).to.throw(error('undefined'));
  109. throwable(() => undefined)();
  110. });
  111. it('requires the option "preHandler" to be a Function or an Array of Function', function () {
  112. const throwable1 = v => () =>
  113. new Route({
  114. method: HttpMethod.GET,
  115. path: '/',
  116. preHandler: v,
  117. handler: () => undefined,
  118. });
  119. const error = v =>
  120. format('The hook "preHandler" should be a Function, but %s given.', v);
  121. expect(throwable1('str')).to.throw(error('"str"'));
  122. expect(throwable1('')).to.throw(error('""'));
  123. expect(throwable1(10)).to.throw(error('10'));
  124. expect(throwable1(0)).to.throw(error('0'));
  125. expect(throwable1(true)).to.throw(error('true'));
  126. expect(throwable1(false)).to.throw(error('false'));
  127. expect(throwable1({})).to.throw(error('Object'));
  128. throwable1([])();
  129. throwable1(() => undefined)();
  130. throwable1(null)();
  131. throwable1(undefined)();
  132. const throwable2 = v => () =>
  133. new Route({
  134. method: HttpMethod.GET,
  135. path: '/',
  136. preHandler: [v],
  137. handler: () => undefined,
  138. });
  139. expect(throwable2('str')).to.throw(error('"str"'));
  140. expect(throwable2('')).to.throw(error('""'));
  141. expect(throwable2(10)).to.throw(error('10'));
  142. expect(throwable2(0)).to.throw(error('0'));
  143. expect(throwable2(true)).to.throw(error('true'));
  144. expect(throwable2(false)).to.throw(error('false'));
  145. expect(throwable2({})).to.throw(error('Object'));
  146. expect(throwable2(null)).to.throw(error('null'));
  147. expect(throwable2([])).to.throw(error('Array'));
  148. expect(throwable2(undefined)).to.throw(error('undefined'));
  149. throwable2(() => undefined)();
  150. });
  151. it('requires the option "postHandler" to be a Function or an Array of Function', function () {
  152. const throwable1 = v => () =>
  153. new Route({
  154. method: HttpMethod.GET,
  155. path: '/',
  156. handler: () => undefined,
  157. postHandler: v,
  158. });
  159. const error = v =>
  160. format('The hook "postHandler" should be a Function, but %s given.', v);
  161. expect(throwable1('str')).to.throw(error('"str"'));
  162. expect(throwable1('')).to.throw(error('""'));
  163. expect(throwable1(10)).to.throw(error('10'));
  164. expect(throwable1(0)).to.throw(error('0'));
  165. expect(throwable1(true)).to.throw(error('true'));
  166. expect(throwable1(false)).to.throw(error('false'));
  167. expect(throwable1({})).to.throw(error('Object'));
  168. throwable1([])();
  169. throwable1(() => undefined)();
  170. throwable1(null)();
  171. throwable1(undefined)();
  172. const throwable2 = v => () =>
  173. new Route({
  174. method: HttpMethod.GET,
  175. path: '/',
  176. handler: () => undefined,
  177. postHandler: [v],
  178. });
  179. expect(throwable2('str')).to.throw(error('"str"'));
  180. expect(throwable2('')).to.throw(error('""'));
  181. expect(throwable2(10)).to.throw(error('10'));
  182. expect(throwable2(0)).to.throw(error('0'));
  183. expect(throwable2(true)).to.throw(error('true'));
  184. expect(throwable2(false)).to.throw(error('false'));
  185. expect(throwable2({})).to.throw(error('Object'));
  186. expect(throwable2(null)).to.throw(error('null'));
  187. expect(throwable2([])).to.throw(error('Array'));
  188. expect(throwable2(undefined)).to.throw(error('undefined'));
  189. throwable2(() => undefined)();
  190. });
  191. it('sets the option "method" in upper case to the "method" property', function () {
  192. const route = new Route({
  193. method: 'post',
  194. path: '/',
  195. handler: () => undefined,
  196. });
  197. expect(route.method).to.be.eq('POST');
  198. });
  199. it('sets the option "path" to the "path" property', function () {
  200. const value = '/myPath';
  201. const route = new Route({
  202. method: HttpMethod.GET,
  203. path: value,
  204. handler: () => undefined,
  205. });
  206. expect(route.path).to.be.eq(value);
  207. });
  208. it('sets the option "handler" to the "handler" property', function () {
  209. const value = () => undefined;
  210. const route = new Route({
  211. method: HttpMethod.GET,
  212. path: '/',
  213. handler: value,
  214. });
  215. expect(route.handler).to.be.eq(value);
  216. });
  217. it('adds a Function to "preHandler" hooks', function () {
  218. const value = () => undefined;
  219. const route = new Route({
  220. method: HttpMethod.GET,
  221. path: '/',
  222. preHandler: value,
  223. handler: () => undefined,
  224. });
  225. expect(route.hookRegistry.hasHook(HookType.PRE_HANDLER, value)).to.be
  226. .true;
  227. });
  228. it('adds Function items of an Array to "preHandler" hooks', function () {
  229. const value = [() => undefined, () => undefined];
  230. const route = new Route({
  231. method: HttpMethod.GET,
  232. path: '/',
  233. preHandler: value,
  234. handler: () => undefined,
  235. });
  236. expect(route.hookRegistry.hasHook(HookType.PRE_HANDLER, value[0])).to.be
  237. .true;
  238. expect(route.hookRegistry.hasHook(HookType.PRE_HANDLER, value[1])).to.be
  239. .true;
  240. });
  241. it('adds a Function to "postHandler" hooks', function () {
  242. const value = () => undefined;
  243. const route = new Route({
  244. method: HttpMethod.GET,
  245. path: '/',
  246. handler: () => undefined,
  247. postHandler: value,
  248. });
  249. expect(route.hookRegistry.hasHook(HookType.POST_HANDLER, value)).to.be
  250. .true;
  251. });
  252. it('adds Function items of an Array to "postHandler" hooks', function () {
  253. const value = [() => undefined, () => undefined];
  254. const route = new Route({
  255. method: HttpMethod.GET,
  256. path: '/',
  257. handler: () => undefined,
  258. postHandler: value,
  259. });
  260. expect(route.hookRegistry.hasHook(HookType.POST_HANDLER, value[0])).to.be
  261. .true;
  262. expect(route.hookRegistry.hasHook(HookType.POST_HANDLER, value[1])).to.be
  263. .true;
  264. });
  265. });
  266. describe('handle', function () {
  267. it('invokes the handler with the given RequestContext and return its result', function () {
  268. const handler = ctx => {
  269. expect(ctx).to.be.instanceof(RequestContext);
  270. return 'OK';
  271. };
  272. const route = new Route({
  273. method: HttpMethod.GET,
  274. path: '/',
  275. handler,
  276. });
  277. const req = createRequestMock();
  278. const res = createResponseMock();
  279. const cnt = new ServiceContainer();
  280. const ctx = new RequestContext(cnt, req, res);
  281. const result = route.handle(ctx);
  282. expect(result).to.be.eq('OK');
  283. });
  284. });
  285. });