route.spec.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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.constructor ' +
  17. 'should be an Object, but %s was 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 was 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 was 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 was 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(
  121. 'The hook "preHandler" should be a Function, but %s was given.',
  122. v,
  123. );
  124. expect(throwable1('str')).to.throw(error('"str"'));
  125. expect(throwable1('')).to.throw(error('""'));
  126. expect(throwable1(10)).to.throw(error('10'));
  127. expect(throwable1(0)).to.throw(error('0'));
  128. expect(throwable1(true)).to.throw(error('true'));
  129. expect(throwable1(false)).to.throw(error('false'));
  130. expect(throwable1({})).to.throw(error('Object'));
  131. throwable1([])();
  132. throwable1(() => undefined)();
  133. throwable1(null)();
  134. throwable1(undefined)();
  135. const throwable2 = v => () =>
  136. new Route({
  137. method: HttpMethod.GET,
  138. path: '/',
  139. preHandler: [v],
  140. handler: () => undefined,
  141. });
  142. expect(throwable2('str')).to.throw(error('"str"'));
  143. expect(throwable2('')).to.throw(error('""'));
  144. expect(throwable2(10)).to.throw(error('10'));
  145. expect(throwable2(0)).to.throw(error('0'));
  146. expect(throwable2(true)).to.throw(error('true'));
  147. expect(throwable2(false)).to.throw(error('false'));
  148. expect(throwable2({})).to.throw(error('Object'));
  149. expect(throwable2(null)).to.throw(error('null'));
  150. expect(throwable2([])).to.throw(error('Array'));
  151. expect(throwable2(undefined)).to.throw(error('undefined'));
  152. throwable2(() => undefined)();
  153. });
  154. it('requires the option "postHandler" to be a Function or an Array of Function', function () {
  155. const throwable1 = v => () =>
  156. new Route({
  157. method: HttpMethod.GET,
  158. path: '/',
  159. handler: () => undefined,
  160. postHandler: v,
  161. });
  162. const error = v =>
  163. format(
  164. 'The hook "postHandler" should be a Function, but %s was given.',
  165. v,
  166. );
  167. expect(throwable1('str')).to.throw(error('"str"'));
  168. expect(throwable1('')).to.throw(error('""'));
  169. expect(throwable1(10)).to.throw(error('10'));
  170. expect(throwable1(0)).to.throw(error('0'));
  171. expect(throwable1(true)).to.throw(error('true'));
  172. expect(throwable1(false)).to.throw(error('false'));
  173. expect(throwable1({})).to.throw(error('Object'));
  174. throwable1([])();
  175. throwable1(() => undefined)();
  176. throwable1(null)();
  177. throwable1(undefined)();
  178. const throwable2 = v => () =>
  179. new Route({
  180. method: HttpMethod.GET,
  181. path: '/',
  182. handler: () => undefined,
  183. postHandler: [v],
  184. });
  185. expect(throwable2('str')).to.throw(error('"str"'));
  186. expect(throwable2('')).to.throw(error('""'));
  187. expect(throwable2(10)).to.throw(error('10'));
  188. expect(throwable2(0)).to.throw(error('0'));
  189. expect(throwable2(true)).to.throw(error('true'));
  190. expect(throwable2(false)).to.throw(error('false'));
  191. expect(throwable2({})).to.throw(error('Object'));
  192. expect(throwable2(null)).to.throw(error('null'));
  193. expect(throwable2([])).to.throw(error('Array'));
  194. expect(throwable2(undefined)).to.throw(error('undefined'));
  195. throwable2(() => undefined)();
  196. });
  197. it('sets the option "method" in upper case to the "method" property', function () {
  198. const route = new Route({
  199. method: 'post',
  200. path: '/',
  201. handler: () => undefined,
  202. });
  203. expect(route.method).to.be.eq('POST');
  204. });
  205. it('sets the option "path" to the "path" property', function () {
  206. const value = '/myPath';
  207. const route = new Route({
  208. method: HttpMethod.GET,
  209. path: value,
  210. handler: () => undefined,
  211. });
  212. expect(route.path).to.be.eq(value);
  213. });
  214. it('sets the option "handler" to the "handler" property', function () {
  215. const value = () => undefined;
  216. const route = new Route({
  217. method: HttpMethod.GET,
  218. path: '/',
  219. handler: value,
  220. });
  221. expect(route.handler).to.be.eq(value);
  222. });
  223. it('adds a Function to "preHandler" hooks', function () {
  224. const value = () => undefined;
  225. const route = new Route({
  226. method: HttpMethod.GET,
  227. path: '/',
  228. preHandler: value,
  229. handler: () => undefined,
  230. });
  231. expect(route.hookRegistry.hasHook(HookType.PRE_HANDLER, value)).to.be
  232. .true;
  233. });
  234. it('adds Function items of an Array to "preHandler" hooks', function () {
  235. const value = [() => undefined, () => undefined];
  236. const route = new Route({
  237. method: HttpMethod.GET,
  238. path: '/',
  239. preHandler: value,
  240. handler: () => undefined,
  241. });
  242. expect(route.hookRegistry.hasHook(HookType.PRE_HANDLER, value[0])).to.be
  243. .true;
  244. expect(route.hookRegistry.hasHook(HookType.PRE_HANDLER, value[1])).to.be
  245. .true;
  246. });
  247. it('adds a Function to "postHandler" hooks', function () {
  248. const value = () => undefined;
  249. const route = new Route({
  250. method: HttpMethod.GET,
  251. path: '/',
  252. handler: () => undefined,
  253. postHandler: value,
  254. });
  255. expect(route.hookRegistry.hasHook(HookType.POST_HANDLER, value)).to.be
  256. .true;
  257. });
  258. it('adds Function items of an Array to "postHandler" hooks', function () {
  259. const value = [() => undefined, () => undefined];
  260. const route = new Route({
  261. method: HttpMethod.GET,
  262. path: '/',
  263. handler: () => undefined,
  264. postHandler: value,
  265. });
  266. expect(route.hookRegistry.hasHook(HookType.POST_HANDLER, value[0])).to.be
  267. .true;
  268. expect(route.hookRegistry.hasHook(HookType.POST_HANDLER, value[1])).to.be
  269. .true;
  270. });
  271. });
  272. describe('handle', function () {
  273. it('invokes the handler with the given RequestContext and return its result', function () {
  274. const handler = ctx => {
  275. expect(ctx).to.be.instanceof(RequestContext);
  276. return 'OK';
  277. };
  278. const route = new Route({
  279. method: HttpMethod.GET,
  280. path: '/',
  281. handler,
  282. });
  283. const req = createRequestMock();
  284. const res = createResponseMock();
  285. const cnt = new ServiceContainer();
  286. const ctx = new RequestContext(cnt, req, res);
  287. const result = route.handle(ctx);
  288. expect(result).to.be.eq('OK');
  289. });
  290. });
  291. });