@ditojs/router 3.0.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +6 -4
  2. package/src/Router.test.js +0 -824
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ditojs/router",
3
- "version": "3.0.0",
3
+ "version": "3.1.1",
4
4
  "type": "module",
5
5
  "description": "Dito.js Router – Dito.js is a declarative and modern web framework, based on Objection.js, Koa.js and Vue.js",
6
6
  "repository": "https://github.com/ditojs/dito/tree/main/packages/router",
@@ -11,7 +11,9 @@
11
11
  ".": "./src/index.js"
12
12
  },
13
13
  "files": [
14
- "src/"
14
+ "src/",
15
+ "!src/**/*.test.js",
16
+ "!src/**/__snapshots__/"
15
17
  ],
16
18
  "engines": {
17
19
  "node": ">= 24.0.0"
@@ -20,7 +22,7 @@
20
22
  "node >= 18"
21
23
  ],
22
24
  "dependencies": {
23
- "@ditojs/utils": "^3.0.0"
25
+ "@ditojs/utils": "^3.1.1"
24
26
  },
25
27
  "keywords": [
26
28
  "route",
@@ -29,5 +31,5 @@
29
31
  "koa",
30
32
  "dito"
31
33
  ],
32
- "gitHead": "399f683a6ca227a03cfc0978fee9055383e6b3d8"
34
+ "gitHead": "acce85bb38d817aab18f9d5d03b3aa9dff00c3f9"
33
35
  }
@@ -1,824 +0,0 @@
1
- import Router from './Router.js'
2
- import { deindent, shuffle } from '@ditojs/utils'
3
- import http from 'http'
4
-
5
- describe('Router', () => {
6
- const handler = () => {}
7
-
8
- let router
9
- beforeEach(() => {
10
- router = new Router()
11
- })
12
-
13
- let result
14
- describe('API', () => {
15
- describe.each([
16
- 'get', 'put', 'post', 'delete', 'head', 'patch', 'options', 'trace',
17
- 'connect'
18
- ])(
19
- 'supports %s() short-cut',
20
- method => {
21
- it('reports correct allowed methods', () => {
22
- router[method]('/', () => {})
23
- expect(router.getAllowedMethods()).toStrictEqual(
24
- [method.toUpperCase()]
25
- )
26
- })
27
- }
28
- )
29
-
30
- it('supports all() short-cut', () => {
31
- router.all('/', () => {})
32
- expect(router.getAllowedMethods()).toEqual(http.METHODS)
33
- })
34
-
35
- it('returns allowed methods', () => {
36
- router.add('GET', '/', () => {})
37
- expect(router.getAllowedMethods()).toStrictEqual(['GET'])
38
- expect(router.getAllowedMethods('/')).toStrictEqual(['GET'])
39
- })
40
-
41
- it('does not count routes without handlers for allowed methods', () => {
42
- router.add('GET', '/')
43
- expect(router.getAllowedMethods('/')).toStrictEqual([])
44
- })
45
-
46
- it('allows excluding methods when getting allowed methods', () => {
47
- router.add('GET', '/', () => {})
48
- router.add('POST', '/', () => {})
49
- expect(router.getAllowedMethods('/', 'GET')).toStrictEqual(['POST'])
50
- })
51
-
52
- it('normalizes paths', () => {
53
- expect(router.normalizePath('/')).toBe('/')
54
- expect(router.normalizePath('/no-trailing/')).toBe('/no-trailing')
55
- expect(router.normalizePath('/no/trailing/')).toBe('/no/trailing')
56
- expect(router.normalizePath('/some/trailing//')).toBe('/some/trailing/')
57
- expect(router.normalizePath('/some/trailing///')).toBe('/some/trailing//')
58
- expect(router.normalizePath('wacky-path')).toBe('/wacky-path')
59
- expect(router.normalizePath('//like-whatever')).toBe('//like-whatever')
60
- })
61
- })
62
-
63
- it('supports prefix for path normalization', () => {
64
- router = new Router({ prefix: '/bla' })
65
- expect(router.normalizePath('/')).toBe('/bla/')
66
- expect(router.normalizePath('/no-trailing/')).toBe('/bla/no-trailing')
67
- expect(router.normalizePath('wacky-path')).toBe('/bla/wacky-path')
68
- expect(router.normalizePath('//like-whatever')).toBe('/bla//like-whatever')
69
- })
70
-
71
- it('does not normalize paths in strict mode', () => {
72
- router = new Router({ strict: true })
73
- expect(router.normalizePath('/')).toBe('/')
74
- expect(router.normalizePath('/trailing/')).toBe('/trailing/')
75
- expect(router.normalizePath('/more/trailing//')).toBe('/more/trailing//')
76
- expect(router.normalizePath('/more/trailing///')).toBe('/more/trailing///')
77
- expect(router.normalizePath('wacky-path')).toBe('wacky-path')
78
- expect(router.normalizePath('//like-whatever')).toBe('//like-whatever')
79
- })
80
-
81
- it('returns empty string with no routes', () => {
82
- expect(router.toString()).toStrictEqual('')
83
- })
84
-
85
- it('handles static routes', () => {
86
- const getHandler = () => {}
87
- const putHandler = () => {}
88
- router.add('GET', '/folders/files/bolt.gif', getHandler)
89
- router.add('PUT', '/folders/files/bolt.gif', putHandler)
90
-
91
- expect(router.toString()).toBe(
92
- deindent`
93
- / children=1
94
- └── folders/files/bolt.gif getHandler() children=0
95
- `.trim()
96
- )
97
-
98
- result = router.find('GET', '/folders/files/bolt.gif')
99
- expect(result.handler).toBe(getHandler)
100
- expect(result.status).toBe(200)
101
-
102
- result = router.find('GET', '/folders/files/bolt.hash.gif')
103
- expect(result.handler).toBeUndefined()
104
- expect(result.allowed).toStrictEqual([])
105
- expect(result.status).toBe(404)
106
-
107
- result = router.find('GET', '/folders/bolt .gif')
108
- expect(result.handler).toBeUndefined()
109
- expect(result.status).toBe(404)
110
-
111
- result = router.find('PUT', '/folders/files/bolt.gif')
112
- expect(result.handler).toBe(putHandler)
113
- expect(result.status).toBe(200)
114
-
115
- result = router.find('PUT', '/folders/files/bolt.hash.gif')
116
- expect(result.handler).toBeUndefined()
117
- expect(result.status).toBe(405)
118
- expect(result.allowed).toStrictEqual([])
119
-
120
- result = router.find('POST', '/folders/files/bolt.gif')
121
- expect(result.handler).toBeUndefined()
122
- expect(result.status).toBe(501)
123
- expect(result.allowed).toStrictEqual(['GET', 'PUT'])
124
- })
125
-
126
- it('handles match-any nodes (catch-all)', () => {
127
- router.add('GET', '/static/**', handler)
128
-
129
- expect(router.toString()).toBe(
130
- deindent`
131
- / children=1
132
- └── static/ children=1
133
- └── ** handler() children=0
134
- `.trim()
135
- )
136
-
137
- result = router.find('GET', '/static')
138
- expect(result.handler).toBeUndefined()
139
-
140
- result = router.find('GET', '/static/*')
141
- expect(result.handler).toBe(handler)
142
-
143
- result = router.find('GET', '/static/js')
144
- expect(result.handler).toBe(handler)
145
- expect(result.params).toEqual({
146
- $$: 'js'
147
- })
148
-
149
- result = router.find('GET', '/static/css')
150
- expect(result.handler).toBe(handler)
151
- expect(result.params).toEqual({
152
- $$: 'css'
153
- })
154
- })
155
-
156
- it('handles match-any nodes (wildcard)', () => {
157
- router.add('GET', '/prefix/*/suffix', handler)
158
-
159
- expect(router.toString()).toBe(
160
- deindent`
161
- / children=1
162
- └── prefix/ children=1
163
- └── * children=1
164
- └── /suffix handler() children=0
165
- `.trim()
166
- )
167
-
168
- result = router.find('GET', '/prefix')
169
- expect(result.handler).toBeUndefined()
170
-
171
- result = router.find('GET', '/prefix/*')
172
- expect(result.handler).toBeUndefined()
173
-
174
- result = router.find('GET', '/prefix/hello/there')
175
- expect(result.handler).toBeUndefined()
176
-
177
- result = router.find('GET', '/prefix/hello/suffix')
178
- expect(result.handler).toBe(handler)
179
- expect(result.params).toEqual({
180
- $: 'hello'
181
- })
182
-
183
- result = router.find('GET', '/prefix/hello/there/suffix')
184
- expect(result.handler).toBeUndefined()
185
- })
186
-
187
- it('handles match-any nodes with suffixes', () => {
188
- createRoutes(router, [
189
- ['GET', '/static/**/suffix', 'one'],
190
- ['GET', '/static/**/suffix/**/more', 'two'],
191
- ['GET', '/static/**/suffix/*/1/:param/2', 'three'],
192
- ['GET', '/static/**/suffix/*/1/:param/2/**/end', 'four']
193
- ])
194
-
195
- expect(router.toString()).toBe(
196
- deindent`
197
- / children=1
198
- └── static/ children=4
199
- ├── **/suffix one() children=0
200
- ├── **/suffix/**/more two() children=0
201
- ├── **/suffix/*/1/:param/2 three() children=0
202
- └── **/suffix/*/1/:param/2/**/end four() children=0
203
- `.trim()
204
- )
205
-
206
- result = router.find('GET', '/static')
207
- expect(result.handler).toBeUndefined()
208
-
209
- result = router.find('GET', '/static/js')
210
- expect(result.handler).toBeUndefined()
211
-
212
- result = router.find('GET', '/static/one/prefix')
213
- expect(result.handler).toBeUndefined()
214
-
215
- result = router.find('GET', '/static/one/two/prefix')
216
- expect(result.handler).toBeUndefined()
217
-
218
- result = router.find('GET', '/static/one/suffix')
219
- expect(result.handler?.name).toBe('one')
220
- expect(result.params).toEqual({
221
- $$: 'one'
222
- })
223
-
224
- result = router.find('GET', '/static/one/two/suffix')
225
- expect(result.handler?.name).toBe('one')
226
- expect(result.params).toEqual({
227
- $$: 'one/two'
228
- })
229
-
230
- result = router.find('GET', '/static/one/two/suffix/three/four')
231
- expect(result.handler).toBeUndefined()
232
-
233
- result = router.find('GET', '/static/one/two/suffix/three/four/more')
234
- expect(result.handler?.name).toBe('two')
235
- expect(result.params).toEqual({
236
- $$0: 'one/two',
237
- $$1: 'three/four'
238
- })
239
-
240
- result = router.find('GET', '/static/one/two/suffix/three/1/bla/2')
241
- expect(result.handler?.name).toBe('three')
242
- expect(result.params).toEqual({
243
- $$: 'one/two',
244
- $: 'three',
245
- param: 'bla'
246
- })
247
-
248
- result = router.find('GET', '/static/one/two/suffix/three/1/bla/3')
249
- expect(result.handler).toBeUndefined()
250
-
251
- result = router.find(
252
- 'GET',
253
- `/static/one/two/suffix/three/1/bla/2/what/ever/end`
254
- )
255
- expect(result.handler?.name).toBe('four')
256
- expect(result.params).toEqual({
257
- $: 'three',
258
- param: 'bla',
259
- $$0: 'one/two',
260
- $$1: 'what/ever'
261
- })
262
- })
263
-
264
- it('Allow match-any child-routes to coexist with other child-routes', () => {
265
- createRoutes(router, [
266
- ['POST', '/api/admin/pages'],
267
- ['POST', '/api/admin/pages/upload/items/**/file'],
268
- ['POST', '/api/admin/pages/upload/items/**/files'],
269
- ['POST', '/api/admin/pages/:id/child-pages']
270
- ])
271
- expect(router.toString('POST')).toBe(
272
- deindent`
273
- / children=1
274
- └── api/admin/pages ƒ() children=1
275
- └── / children=2
276
- ├── upload/items/ children=2
277
- │ ├── **/file ƒ() children=0
278
- │ └── **/files ƒ() children=0
279
- └── :id children=1
280
- └── /child-pages ƒ() children=0
281
- `.trim()
282
- )
283
-
284
- result = router.find('POST', '/api/admin/pages/upload/items/1/file')
285
- expect(result.handler).not.toBeUndefined()
286
-
287
- result = router.find('POST', '/api/admin/pages/upload/items/1/2/file')
288
- expect(result.handler).not.toBeUndefined()
289
- })
290
-
291
- it('handles resources', () => {
292
- createRoutes(router, [
293
- ['GET', '/', 'root'],
294
- ['GET', '/geocoder', 'geocoder'],
295
- ['GET', '/geocoder/new', 'newGeocoder'],
296
- ['GET', '/geocoder/notify', 'notifyGeocoder'],
297
- // ['GET', '/geocoder/nnn', 'nnnGeocoder'],
298
- ['GET', '/geocoder/edit', 'editGeocoder'],
299
- ['GET', '/geocoder/edit/email', 'editEmailGeocoder'],
300
- ['GET', '/geocoder/edit/:item', 'editItemGeocoder'],
301
- ['GET', '/geocoder/exchange', 'exchangeGeocoder'],
302
- ['GET', '/geocoder/exchange/email', 'exchangeEmailGeocoder'],
303
- ['GET', '/geocoder/exchange/:item', 'exchangeItemGeocoder'],
304
- ['GET', '/geocoder/:id/echo', 'echoGeocoder'],
305
- ['GET', '/geocoder/:action', 'actionGeocoder'],
306
- ['GET', '/geocoder/**', 'anyGeocoder']
307
- ])
308
-
309
- expect(router.toString()).toBe(
310
- deindent`
311
- / root() children=1
312
- └── geocoder geocoder() children=1
313
- └── / children=4
314
- ├── n children=2
315
- │ ├── ew newGeocoder() children=0
316
- │ └── otify notifyGeocoder() children=0
317
- ├── e children=2
318
- │ ├── dit editGeocoder() children=1
319
- │ │ └── / children=2
320
- │ │ ├── email editEmailGeocoder() children=0
321
- │ │ └── :item editItemGeocoder() children=0
322
- │ └── xchange exchangeGeocoder() children=1
323
- │ └── / children=2
324
- │ ├── email exchangeEmailGeocoder() children=0
325
- │ └── :item exchangeItemGeocoder() children=0
326
- ├── :action actionGeocoder() children=1
327
- │ └── /echo echoGeocoder() children=0
328
- └── ** anyGeocoder() children=0
329
- `.trim()
330
- )
331
- result = router.find('GET', '')
332
- expect(result.handler).not.toBeUndefined()
333
- expect(result.params).toEqual({})
334
-
335
- result = router.find('GET', '/')
336
- expect(result.handler).not.toBeUndefined()
337
- expect(result.handler.name).toBe('root')
338
- expect(result.params).toEqual({})
339
-
340
- result = router.find('GET', '/geocoder/delete')
341
- expect(result.handler).not.toBeUndefined()
342
- expect(result.handler.name).toBe('actionGeocoder')
343
- expect(result.params).toEqual({ action: 'delete' })
344
-
345
- result = router.find('GET', '/geocoder/delete/any')
346
- expect(result.handler.name).toBe('anyGeocoder')
347
- expect(result.params).toEqual({ $$: 'delete/any' })
348
-
349
- result = router.find('GET', '/geocoder/any/action')
350
- expect(result.handler).not.toBeUndefined()
351
- expect(result.handler.name).toBe('anyGeocoder')
352
- expect(result.params).toEqual({ $$: 'any/action' })
353
-
354
- result = router.find('GET', '/geocoder/exchange/trekjs')
355
- expect(result.handler).not.toBeUndefined()
356
- expect(result.handler.name).toBe('exchangeItemGeocoder')
357
- expect(result.params).toEqual({ item: 'trekjs' })
358
-
359
- result = router.find('GET', '/geocoder/exchange/trekjs/any')
360
- expect(result.handler.name).toBe('anyGeocoder')
361
-
362
- result = router.find('GET', '/geocoder/exchange/email')
363
- expect(result.handler).not.toBeUndefined()
364
- expect(result.handler.name).toBe('exchangeEmailGeocoder')
365
-
366
- result = router.find('GET', '/geocoder/exchange/email/any')
367
- expect(result.handler.name).toBe('anyGeocoder')
368
-
369
- result = router.find('GET', '/geocoder/exchange')
370
- expect(result.handler).not.toBeUndefined()
371
- expect(result.handler.name).toBe('exchangeGeocoder')
372
-
373
- result = router.find('GET', '/geocoder/edit/trekjs')
374
- expect(result.handler).not.toBeUndefined()
375
- expect(result.handler.name).toBe('editItemGeocoder')
376
-
377
- result = router.find('GET', '/geocoder/edit/email')
378
- expect(result.handler).not.toBeUndefined()
379
- expect(result.handler.name).toBe('editEmailGeocoder')
380
-
381
- result = router.find('GET', '/geocoder/edit/email/any')
382
- expect(result.handler.name).toBe('anyGeocoder')
383
-
384
- result = router.find('GET', '/geocoder/edit')
385
- expect(result.handler).not.toBeUndefined()
386
- expect(result.handler.name).toBe('editGeocoder')
387
-
388
- result = router.find('GET', '/geocoder/new')
389
- expect(result.handler).not.toBeUndefined()
390
- expect(result.handler.name).toBe('newGeocoder')
391
-
392
- result = router.find('GET', '/geocoder/nnn')
393
- expect(result.handler).not.toBeUndefined()
394
- expect(result.handler.name).toBe('actionGeocoder')
395
-
396
- result = router.find('GET', '/geocoder/new/any')
397
- expect(result.handler.name).toBe('anyGeocoder')
398
-
399
- result = router.find('GET', '/geocoder')
400
- expect(result.handler).not.toBeUndefined()
401
- expect(result.handler.name).toBe('geocoder')
402
-
403
- result = router.find('GET', '/geocoder//')
404
- expect(result.handler).toBeUndefined()
405
-
406
- result = router.find('GET', '/repos')
407
- expect(result.handler).toBeUndefined()
408
- })
409
-
410
- it('handles nested resources', () => {
411
- createRoutes(router, [
412
- ['GET', '/users', 'users'],
413
- ['GET', '/users/new', 'newUser'],
414
- ['GET', '/users/noi', 'newUser'],
415
- ['GET', '/users/nei', 'newUser'],
416
- ['GET', '/users/:id', 'user'],
417
- ['GET', '/users/:id/edit', 'editUser'],
418
- ['GET', '/users/:id/:hello/:good/:bad/ddd', 'editUser'],
419
- ['GET', '/users/:id/:action', 'actionUser'],
420
- ['GET', '/users/:userId/photos/:id', 'photo'],
421
- ['GET', '/users/:userId/books/:id', 'book'],
422
- ['GET', '/users/**', 'anyUser']
423
- ])
424
-
425
- expect(router.toString()).toBe(
426
- deindent`
427
- / children=1
428
- └── users users() children=1
429
- └── / children=3
430
- ├── n children=2
431
- │ ├── e children=2
432
- │ │ ├── w newUser() children=0
433
- │ │ └── i newUser() children=0
434
- │ └── oi newUser() children=0
435
- ├── :userId user() children=1
436
- │ └── / children=4
437
- │ ├── edit editUser() children=0
438
- │ ├── :action actionUser() children=1
439
- │ │ └── / children=1
440
- │ │ └── :good children=1
441
- │ │ └── / children=1
442
- │ │ └── :bad children=1
443
- │ │ └── /ddd editUser() children=0
444
- │ ├── photos/ children=1
445
- │ │ └── :id photo() children=0
446
- │ └── books/ children=1
447
- │ └── :id book() children=0
448
- └── ** anyUser() children=0
449
- `.trim()
450
- )
451
-
452
- result = router.find('GET', '/users/610/books/987/edit')
453
- expect(result.handler).not.toBeUndefined()
454
- expect(result.handler.name).toBe('anyUser')
455
- expect(result.params).toEqual({ $$: '610/books/987/edit' })
456
-
457
- result = router.find('GET', '/users/610/books/987')
458
- expect(result.handler).not.toBeUndefined()
459
- expect(result.handler.name).toBe('book')
460
- expect(result.params).toEqual({ userId: '610', id: '987' })
461
-
462
- result = router.find('GET', '/users/610/photos')
463
- expect(result.handler).not.toBeUndefined()
464
- expect(result.handler.name).toBe('actionUser')
465
- expect(result.params).toEqual({ id: '610', action: 'photos' })
466
-
467
- result = router.find('GET', '/users/610/photos/1024')
468
- expect(result.handler).not.toBeUndefined()
469
- expect(result.handler.name).toBe('photo')
470
- expect(result.params).toEqual({ userId: '610', id: '1024' })
471
-
472
- result = router.find('GET', '/users/2323/delete')
473
- expect(result.handler).not.toBeUndefined()
474
- expect(result.handler.name).toBe('actionUser')
475
- expect(result.params).toEqual({ id: '2323', action: 'delete' })
476
-
477
- result = router.find('GET', '/users/377/edit')
478
- expect(result.handler).not.toBeUndefined()
479
- expect(result.handler.name).toBe('editUser')
480
- expect(result.params).toEqual({ id: '377' })
481
-
482
- result = router.find('GET', '/users/233')
483
- expect(result.handler).not.toBeUndefined()
484
- expect(result.handler.name).toBe('user')
485
- expect(result.params).toEqual({ id: '233' })
486
-
487
- result = router.find('GET', '/users/new/preview')
488
- expect(result.handler).not.toBeUndefined()
489
- expect(result.handler.name).toBe('actionUser')
490
- expect(result.params).toEqual({ id: 'new', action: 'preview' })
491
-
492
- result = router.find('GET', '/users/news')
493
- expect(result.handler).not.toBeUndefined()
494
- expect(result.handler.name).toBe('user')
495
- expect(result.params).toEqual({ id: 'news' })
496
-
497
- result = router.find('GET', '/users/new')
498
- expect(result.handler).not.toBeUndefined()
499
- expect(result.handler.name).toBe('newUser')
500
-
501
- result = router.find('GET', '/users')
502
- expect(result.handler).not.toBeUndefined()
503
- expect(result.handler.name).toBe('users')
504
-
505
- result = router.find('GET', '/user')
506
- expect(result.handler).toBeUndefined()
507
-
508
- result = router.find('GET', '/repos')
509
- expect(result.handler).toBeUndefined()
510
- })
511
-
512
- describe('handles multiple resources', () => {
513
- const routes = [
514
- ['GET', '/users', 'users'],
515
- ['GET', '/users/new', 'newUser'],
516
- ['GET', '/users/:id', 'user'],
517
- ['GET', '/users/:id/:action', 'actionUser'],
518
- ['GET', '/users/:id/edit', 'editUser'],
519
- ['GET', '/users/:id/change', 'changeUser'],
520
- ['GET', '/users/:id/event', 'eventUser'],
521
- ['GET', '/photos', 'photos'],
522
- ['GET', '/photos/new', 'newPhoto'],
523
- ['GET', '/photos/:id', 'photo'],
524
- ['GET', '/photos/:id/:action', 'actionPhoto'],
525
- ['GET', '/photos/:id/edit', 'editPhoto'],
526
- ['GET', '/photos/:id/change', 'changePhoto'],
527
- ['GET', '/photos/:id/event', 'eventPhoto'],
528
- ['GET', '/books', 'books'],
529
- ['GET', '/books/new', 'newBook'],
530
- ['GET', '/books/:id', 'book'],
531
- ['GET', '/books/:id/:action', 'actionBook'],
532
- ['GET', '/books/:id/edit', 'editBook'],
533
- ['GET', '/books/:id/change', 'changeBook'],
534
- ['GET', '/books/:id/event', 'eventBook']
535
- ]
536
-
537
- it('parses routes into the correct tree', () => {
538
- createRoutes(router, routes)
539
- expect(router.toString()).toBe(
540
- deindent`
541
- / children=3
542
- ├── users users() children=1
543
- │ └── / children=2
544
- │ ├── new newUser() children=0
545
- │ └── :id user() children=1
546
- │ └── / children=3
547
- │ ├── :action actionUser() children=0
548
- │ ├── e children=2
549
- │ │ ├── dit editUser() children=0
550
- │ │ └── vent eventUser() children=0
551
- │ └── change changeUser() children=0
552
- ├── photos photos() children=1
553
- │ └── / children=2
554
- │ ├── new newPhoto() children=0
555
- │ └── :id photo() children=1
556
- │ └── / children=3
557
- │ ├── :action actionPhoto() children=0
558
- │ ├── e children=2
559
- │ │ ├── dit editPhoto() children=0
560
- │ │ └── vent eventPhoto() children=0
561
- │ └── change changePhoto() children=0
562
- └── books books() children=1
563
- └── / children=2
564
- ├── new newBook() children=0
565
- └── :id book() children=1
566
- └── / children=3
567
- ├── :action actionBook() children=0
568
- ├── e children=2
569
- │ ├── dit editBook() children=0
570
- │ └── vent eventBook() children=0
571
- └── change changeBook() children=0
572
- `.trim()
573
- )
574
- })
575
-
576
- it('results in expected parameters', () => {
577
- createRoutes(router, shuffle(routes))
578
-
579
- result = router.find('GET', '/books/377/change')
580
- expect(result.handler).not.toBeUndefined()
581
- expect(result.handler.name).toBe('changeBook')
582
- expect(result.params).toEqual({ id: '377' })
583
-
584
- result = router.find('GET', '/books/377/event')
585
- expect(result.handler).not.toBeUndefined()
586
- expect(result.handler.name).toBe('eventBook')
587
- expect(result.params).toEqual({ id: '377' })
588
-
589
- result = router.find('GET', '/books/377/edit')
590
- expect(result.handler).not.toBeUndefined()
591
- expect(result.handler.name).toBe('editBook')
592
- expect(result.params).toEqual({ id: '377' })
593
-
594
- result = router.find('GET', '/books/233')
595
- expect(result.handler).not.toBeUndefined()
596
- expect(result.handler.name).toBe('book')
597
- expect(result.params).toEqual({ id: '233' })
598
-
599
- result = router.find('GET', '/books/new')
600
- expect(result.handler.name).toBe('newBook')
601
- expect(result.handler).not.toBeUndefined()
602
-
603
- result = router.find('GET', '/books')
604
- expect(result.handler).not.toBeUndefined()
605
- expect(result.handler.name).toBe('books')
606
-
607
- result = router.find('GET', '/users/377/change')
608
- expect(result.handler).not.toBeUndefined()
609
- expect(result.handler.name).toBe('changeUser')
610
- expect(result.params).toEqual({ id: '377' })
611
-
612
- result = router.find('GET', '/users/377/event')
613
- expect(result.handler).not.toBeUndefined()
614
- expect(result.handler.name).toBe('eventUser')
615
- expect(result.params).toEqual({ id: '377' })
616
-
617
- result = router.find('GET', '/users/377/edit')
618
- expect(result.handler).not.toBeUndefined()
619
- expect(result.handler.name).toBe('editUser')
620
- expect(result.params).toEqual({ id: '377' })
621
-
622
- result = router.find('GET', '/users/233')
623
- expect(result.handler).not.toBeUndefined()
624
- expect(result.handler.name).toBe('user')
625
- expect(result.params).toEqual({ id: '233' })
626
-
627
- result = router.find('GET', '/users/new')
628
- expect(result.handler.name).toBe('newUser')
629
- expect(result.handler).not.toBeUndefined()
630
-
631
- result = router.find('GET', '/users')
632
- expect(result.handler).not.toBeUndefined()
633
- expect(result.handler.name).toBe('users')
634
-
635
- result = router.find('GET', '/photos/377/event')
636
- expect(result.handler).not.toBeUndefined()
637
- expect(result.handler.name).toBe('eventPhoto')
638
- expect(result.params).toEqual({ id: '377' })
639
-
640
- result = router.find('GET', '/photos/377/change')
641
- expect(result.handler).not.toBeUndefined()
642
- expect(result.handler.name).toBe('changePhoto')
643
- expect(result.params).toEqual({ id: '377' })
644
-
645
- result = router.find('GET', '/photos/377/edit')
646
- expect(result.handler).not.toBeUndefined()
647
- expect(result.handler.name).toBe('editPhoto')
648
- expect(result.params).toEqual({ id: '377' })
649
-
650
- result = router.find('GET', '/photos/233')
651
- expect(result.handler).not.toBeUndefined()
652
- expect(result.handler.name).toBe('photo')
653
- expect(result.params).toEqual({ id: '233' })
654
-
655
- result = router.find('GET', '/photos/new')
656
- expect(result.handler.name).toBe('newPhoto')
657
- expect(result.handler).not.toBeUndefined()
658
-
659
- result = router.find('GET', '/photos')
660
- expect(result.handler).not.toBeUndefined()
661
- expect(result.handler.name).toBe('photos')
662
- })
663
- })
664
-
665
- describe('handles namespaces', () => {
666
- const routes = [
667
- ['GET', '/admin/articles', 'articles'],
668
- ['GET', '/admin/articles/new', 'newArticle'],
669
- ['GET', '/admin/articles/:id', 'article'],
670
- ['GET', '/admin/articles/:id/edit', 'editArticle']
671
- ]
672
-
673
- it('parses routes into the correct tree', () => {
674
- createRoutes(router, routes)
675
- expect(router.toString()).toBe(
676
- deindent`
677
- / children=1
678
- └── admin/articles articles() children=1
679
- └── / children=2
680
- ├── new newArticle() children=0
681
- └── :id article() children=1
682
- └── /edit editArticle() children=0
683
- `.trim()
684
- )
685
- })
686
-
687
- it('results in expected parameters', () => {
688
- createRoutes(router, shuffle(routes))
689
-
690
- result = router.find('GET', '/admin/articles/377/edit')
691
- expect(result.handler).not.toBeUndefined()
692
- expect(result.handler.name).toBe('editArticle')
693
- expect(result.params).toEqual({ id: '377' })
694
-
695
- result = router.find('GET', '/admin/articles/233')
696
- expect(result.handler).not.toBeUndefined()
697
- expect(result.handler.name).toBe('article')
698
- expect(result.params).toEqual({ id: '233' })
699
-
700
- result = router.find('GET', '/admin/articles/new')
701
- expect(result.handler).not.toBeUndefined()
702
- expect(result.handler.name).toBe('newArticle')
703
-
704
- result = router.find('GET', '/admin/articles')
705
- expect(result.handler).not.toBeUndefined()
706
- expect(result.handler.name).toBe('articles')
707
- })
708
- })
709
-
710
- describe('handles multiple nested resources', () => {
711
- const routes = [
712
- ['GET', '/magazines/:mid/articles', 'articles'],
713
- ['GET', '/magazines/:mid/articles/new', 'newArticle'],
714
- ['GET', '/magazines/:mid/articles/:id', 'article'],
715
- ['GET', '/magazines/:mid/articles/:id/edit', 'editArticle'],
716
- ['GET', '/magazines/:m_id/photos', 'photos'],
717
- ['GET', '/magazines/:m_id/photos/new', 'newPhoto'],
718
- ['GET', '/magazines/:m_id/photos/:id', 'photo'],
719
- ['GET', '/magazines/:m_id/photos/:id/edit', 'editPhoto']
720
- ]
721
-
722
- it('parses routes into the correct tree', () => {
723
- createRoutes(router, routes)
724
- expect(router.toString()).toBe(
725
- deindent`
726
- / children=1
727
- └── magazines/ children=1
728
- └── :m_id children=1
729
- └── / children=2
730
- ├── articles articles() children=1
731
- │ └── / children=2
732
- │ ├── new newArticle() children=0
733
- │ └── :id article() children=1
734
- │ └── /edit editArticle() children=0
735
- └── photos photos() children=1
736
- └── / children=2
737
- ├── new newPhoto() children=0
738
- └── :id photo() children=1
739
- └── /edit editPhoto() children=0
740
- `.trim()
741
- )
742
- })
743
-
744
- it('results in expected parameters', () => {
745
- createRoutes(router, shuffle(routes))
746
-
747
- result = router.find('GET', '/magazines/233/articles/377')
748
- expect(result.handler).not.toBeUndefined()
749
- expect(result.handler.name).toBe('article')
750
- expect(result.params).toEqual({ mid: '233', id: '377' })
751
-
752
- result = router.find('GET', '/magazines/233/articles/377/edit')
753
- expect(result.handler).not.toBeUndefined()
754
- expect(result.handler.name).toBe('editArticle')
755
- expect(result.params).toEqual({ mid: '233', id: '377' })
756
-
757
- result = router.find('GET', '/magazines/233/articles/new')
758
- expect(result.handler).not.toBeUndefined()
759
- expect(result.handler.name).toBe('newArticle')
760
- expect(result.params).toEqual({ mid: '233' })
761
-
762
- result = router.find('GET', '/magazines/233/articles')
763
- expect(result.handler).not.toBeUndefined()
764
- expect(result.handler.name).toBe('articles')
765
- expect(result.params).toEqual({ mid: '233' })
766
-
767
- result = router.find('GET', '/magazines/233/photos/377/edit')
768
- expect(result.handler).not.toBeUndefined()
769
- expect(result.handler.name).toBe('editPhoto')
770
- expect(result.params).toEqual({ m_id: '233', id: '377' })
771
-
772
- result = router.find('GET', '/magazines/233/photos/377')
773
- expect(result.handler).not.toBeUndefined()
774
- expect(result.handler.name).toBe('photo')
775
- expect(result.params).toEqual({ m_id: '233', id: '377' })
776
-
777
- result = router.find('GET', '/magazines/233/photos/new')
778
- expect(result.handler).not.toBeUndefined()
779
- expect(result.handler.name).toBe('newPhoto')
780
- expect(result.params).toEqual({ m_id: '233' })
781
-
782
- result = router.find('GET', '/magazines/233/photos')
783
- expect(result.handler).not.toBeUndefined()
784
- expect(result.handler.name).toBe('photos')
785
- expect(result.params).toEqual({ m_id: '233' })
786
- })
787
- })
788
-
789
- it('identifies unnamed handlers', () => {
790
- router.add('GET', '/function', function () {})
791
- router.add('GET', '/closure', () => {})
792
- expect(router.toString()).toBe(
793
- deindent`
794
- / children=2
795
- ├── function ƒ() children=0
796
- └── closure ƒ() children=0
797
- `.trim()
798
- )
799
- })
800
-
801
- it(`deals with paths not starting with '/'`, () => {
802
- router.add('GET', '/users', () => {})
803
- router.add('GET', '/wacky-path', () => {})
804
- expect(router.toString()).toBe(
805
- deindent`
806
- / children=2
807
- ├── users ƒ() children=0
808
- └── wacky-path ƒ() children=0
809
- `.trim()
810
- )
811
- })
812
- })
813
-
814
- function createFunc(name) {
815
- return new Function(
816
- `return ${name ? `function ${name}(){}` : '() => {}'}`
817
- )()
818
- }
819
-
820
- function createRoutes(router, routes) {
821
- routes.forEach(([method, path, name]) => {
822
- router.add(method, path, createFunc(name))
823
- })
824
- }