@esmx/router 3.0.0-rc.27 → 3.0.0-rc.30

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 (59) hide show
  1. package/README.zh-CN.md +82 -1
  2. package/dist/index.d.ts +1 -2
  3. package/dist/index.mjs +0 -1
  4. package/package.json +4 -4
  5. package/src/index.ts +0 -3
  6. package/dist/index.test.d.ts +0 -1
  7. package/dist/index.test.mjs +0 -8
  8. package/dist/location.test.d.ts +0 -8
  9. package/dist/location.test.mjs +0 -370
  10. package/dist/matcher.test.d.ts +0 -1
  11. package/dist/matcher.test.mjs +0 -1492
  12. package/dist/micro-app.dom.test.d.ts +0 -1
  13. package/dist/micro-app.dom.test.mjs +0 -532
  14. package/dist/navigation.test.d.ts +0 -1
  15. package/dist/navigation.test.mjs +0 -681
  16. package/dist/route-task.test.d.ts +0 -1
  17. package/dist/route-task.test.mjs +0 -673
  18. package/dist/route-transition.test.d.ts +0 -1
  19. package/dist/route-transition.test.mjs +0 -146
  20. package/dist/route.test.d.ts +0 -1
  21. package/dist/route.test.mjs +0 -1664
  22. package/dist/router-back.test.d.ts +0 -1
  23. package/dist/router-back.test.mjs +0 -361
  24. package/dist/router-forward.test.d.ts +0 -1
  25. package/dist/router-forward.test.mjs +0 -376
  26. package/dist/router-go.test.d.ts +0 -1
  27. package/dist/router-go.test.mjs +0 -73
  28. package/dist/router-guards-cleanup.test.d.ts +0 -1
  29. package/dist/router-guards-cleanup.test.mjs +0 -437
  30. package/dist/router-push.test.d.ts +0 -1
  31. package/dist/router-push.test.mjs +0 -115
  32. package/dist/router-replace.test.d.ts +0 -1
  33. package/dist/router-replace.test.mjs +0 -114
  34. package/dist/router-resolve.test.d.ts +0 -1
  35. package/dist/router-resolve.test.mjs +0 -393
  36. package/dist/router-restart-app.dom.test.d.ts +0 -1
  37. package/dist/router-restart-app.dom.test.mjs +0 -616
  38. package/dist/router-window-navigation.test.d.ts +0 -1
  39. package/dist/router-window-navigation.test.mjs +0 -359
  40. package/dist/util.test.d.ts +0 -1
  41. package/dist/util.test.mjs +0 -1020
  42. package/src/index.test.ts +0 -9
  43. package/src/location.test.ts +0 -406
  44. package/src/matcher.test.ts +0 -1685
  45. package/src/micro-app.dom.test.ts +0 -708
  46. package/src/navigation.test.ts +0 -858
  47. package/src/route-task.test.ts +0 -901
  48. package/src/route-transition.test.ts +0 -178
  49. package/src/route.test.ts +0 -2014
  50. package/src/router-back.test.ts +0 -487
  51. package/src/router-forward.test.ts +0 -506
  52. package/src/router-go.test.ts +0 -91
  53. package/src/router-guards-cleanup.test.ts +0 -595
  54. package/src/router-push.test.ts +0 -140
  55. package/src/router-replace.test.ts +0 -139
  56. package/src/router-resolve.test.ts +0 -475
  57. package/src/router-restart-app.dom.test.ts +0 -783
  58. package/src/router-window-navigation.test.ts +0 -457
  59. package/src/util.test.ts +0 -1262
@@ -1,475 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, test } from 'vitest';
2
- import { Router } from './router';
3
- import { RouteType, RouterMode } from './types';
4
- import type { Route, RouteConfig } from './types';
5
-
6
- const createTestRouter = (): Router => {
7
- return new Router({
8
- mode: RouterMode.memory,
9
- base: new URL('http://localhost:3000/'),
10
- routes: createTestRoutes()
11
- });
12
- };
13
-
14
- const createTestRoutes = (): RouteConfig[] => {
15
- return [
16
- {
17
- path: '/',
18
- component: () => 'Home',
19
- meta: { title: 'Home Page' }
20
- },
21
- {
22
- path: '/about',
23
- component: () => 'About',
24
- meta: { title: 'About Page', requiresAuth: false }
25
- },
26
- {
27
- path: '/user/:id',
28
- component: () => 'User',
29
- meta: { title: 'User Profile', requiresAuth: true },
30
- children: [
31
- {
32
- path: '/profile',
33
- component: () => 'UserProfile',
34
- meta: { section: 'profile' }
35
- },
36
- {
37
- path: '/settings',
38
- component: () => 'UserSettings',
39
- meta: { section: 'settings' }
40
- }
41
- ]
42
- },
43
- {
44
- path: '/admin',
45
- component: () => 'Admin',
46
- meta: { requiresAuth: true, role: 'admin' },
47
- children: [
48
- {
49
- path: '/users',
50
- component: () => 'AdminUsers',
51
- meta: { section: 'users' }
52
- },
53
- {
54
- path: '/settings',
55
- component: () => 'AdminSettings',
56
- meta: { section: 'settings' }
57
- }
58
- ]
59
- },
60
- {
61
- path: '/products/:category/:id',
62
- component: () => 'Product',
63
- meta: { title: 'Product Detail' }
64
- }
65
- ];
66
- };
67
-
68
- const createTestCases = () => {
69
- return {
70
- validPaths: [
71
- { path: '/', shouldMatch: true },
72
- { path: '/about', shouldMatch: true },
73
- { path: '/user/123', shouldMatch: true },
74
- { path: '/admin/users', shouldMatch: true }
75
- ],
76
- invalidPaths: [
77
- { path: '/invalid', shouldMatch: false },
78
- { path: '/user', shouldMatch: false } // Missing required parameter
79
- ]
80
- };
81
- };
82
-
83
- describe('Router.resolve method tests', () => {
84
- let router: Router;
85
-
86
- beforeEach(async () => {
87
- router = createTestRouter();
88
- await router.replace('/');
89
- });
90
-
91
- afterEach(() => {
92
- router.destroy();
93
- });
94
-
95
- describe('Core resolution functionality', () => {
96
- test('should return complete Route object with all required properties', () => {
97
- const route: Route = router.resolve('/about');
98
-
99
- expect(route).toBeInstanceOf(Object);
100
- expect(route.type).toBe('push');
101
- expect(route.path).toBe('/about');
102
- expect(route.fullPath).toBe('/about');
103
- expect(route.url).toBeInstanceOf(URL);
104
- expect(route.params).toBeInstanceOf(Object);
105
- expect(route.query).toBeInstanceOf(Object);
106
- expect(route.meta).toBeInstanceOf(Object);
107
- expect(route.matched).toBeInstanceOf(Array);
108
- });
109
-
110
- test('should not trigger actual navigation', () => {
111
- const originalPath: string = router.route.path;
112
-
113
- router.resolve('/about');
114
- router.resolve('/user/123');
115
- router.resolve('/admin/users');
116
-
117
- expect(router.route.path).toBe(originalPath);
118
- });
119
-
120
- test('should correctly resolve string path', () => {
121
- const route: Route = router.resolve('/user/123');
122
-
123
- expect(route.path).toBe('/user/123');
124
- expect(route.params.id).toBe('123');
125
- expect(route.matched.length).toBeGreaterThan(0);
126
- expect(route.config).not.toBeNull();
127
- });
128
-
129
- test('should correctly resolve object configuration', () => {
130
- const route: Route = router.resolve({
131
- path: '/user/456',
132
- query: { tab: 'profile', active: 'true' },
133
- hash: '#section1'
134
- });
135
-
136
- expect(route.path).toBe('/user/456');
137
- expect(route.params.id).toBe('456');
138
- expect(route.query.tab).toBe('profile');
139
- expect(route.query.active).toBe('true');
140
- expect(route.url.hash).toBe('#section1');
141
- expect(route.fullPath).toBe(
142
- '/user/456?tab=profile&active=true#section1'
143
- );
144
- });
145
- });
146
-
147
- describe('Path resolution and parameter extraction', () => {
148
- test('should correctly resolve single path parameter', () => {
149
- const route: Route = router.resolve('/user/123');
150
-
151
- expect(route.params.id).toBe('123');
152
- expect(route.path).toBe('/user/123');
153
- expect(route.matched.length).toBe(1);
154
- });
155
-
156
- test('should correctly resolve multiple path parameters', () => {
157
- const route: Route = router.resolve(
158
- '/products/electronics/laptop-123'
159
- );
160
-
161
- expect(route.params.category).toBe('electronics');
162
- expect(route.params.id).toBe('laptop-123');
163
- expect(route.path).toBe('/products/electronics/laptop-123');
164
- });
165
-
166
- test('should correctly resolve query parameters', () => {
167
- const route: Route = router.resolve(
168
- '/about?lang=en&theme=dark&debug=true'
169
- );
170
-
171
- expect(route.query.lang).toBe('en');
172
- expect(route.query.theme).toBe('dark');
173
- expect(route.query.debug).toBe('true');
174
- expect(route.queryArray.lang).toEqual(['en']);
175
- expect(route.queryArray.theme).toEqual(['dark']);
176
- });
177
-
178
- test('should correctly handle duplicate query parameters', () => {
179
- const route: Route = router.resolve(
180
- '/about?tags=vue&tags=router&tags=test'
181
- );
182
-
183
- expect(route.query.tags).toBe('vue'); // First value
184
- expect(route.queryArray.tags).toEqual(['vue', 'router', 'test']);
185
- });
186
-
187
- test('should correctly resolve hash fragment', () => {
188
- const route: Route = router.resolve('/about#introduction');
189
-
190
- expect(route.url.hash).toBe('#introduction');
191
- expect(route.fullPath).toBe('/about#introduction');
192
- });
193
-
194
- test('should correctly handle complex URL combination', () => {
195
- const route: Route = router.resolve(
196
- '/user/123?tab=profile&edit=true#personal-info'
197
- );
198
-
199
- expect(route.params.id).toBe('123');
200
- expect(route.query.tab).toBe('profile');
201
- expect(route.query.edit).toBe('true');
202
- expect(route.url.hash).toBe('#personal-info');
203
- expect(route.fullPath).toBe(
204
- '/user/123?tab=profile&edit=true#personal-info'
205
- );
206
- });
207
- });
208
-
209
- describe('Nested route resolution', () => {
210
- test('should correctly resolve nested routes', () => {
211
- const route: Route = router.resolve('/user/123/profile');
212
-
213
- expect(route.params.id).toBe('123');
214
- expect(route.path).toBe('/user/123/profile');
215
- expect(route.matched.length).toBe(2); // Parent route + child route
216
- expect(route.config?.meta?.section).toBe('profile');
217
- });
218
-
219
- test('should correctly resolve deeply nested routes', () => {
220
- const route: Route = router.resolve('/admin/users');
221
-
222
- expect(route.path).toBe('/admin/users');
223
- expect(route.matched.length).toBe(2);
224
- expect(route.config?.meta?.section).toBe('users');
225
- });
226
-
227
- test('should return last matched route configuration', () => {
228
- const route: Route = router.resolve('/user/123/settings');
229
-
230
- expect(route.config?.meta?.section).toBe('settings');
231
- expect(route.meta.section).toBe('settings');
232
- expect(route.meta.title).toBeUndefined();
233
- });
234
- });
235
-
236
- describe('Meta information handling', () => {
237
- test('should correctly return route meta information', () => {
238
- const route: Route = router.resolve('/about');
239
-
240
- expect(route.meta.title).toBe('About Page');
241
- expect(route.meta.requiresAuth).toBe(false);
242
- });
243
-
244
- test('should return last matched route meta in nested routes', () => {
245
- const route: Route = router.resolve('/user/123/profile');
246
-
247
- expect(route.meta.section).toBe('profile');
248
- expect(route.meta.title).toBeUndefined();
249
- expect(route.meta.requiresAuth).toBeUndefined();
250
- });
251
-
252
- test('should return empty object when no meta information exists', () => {
253
- const testRouter: Router = new Router({
254
- mode: RouterMode.memory,
255
- base: new URL('http://localhost:3000/'),
256
- routes: [
257
- {
258
- path: '/no-meta',
259
- component: () => 'NoMeta'
260
- }
261
- ]
262
- });
263
-
264
- const route: Route = testRouter.resolve('/no-meta');
265
- expect(route.meta).toEqual({});
266
-
267
- testRouter.destroy();
268
- });
269
- });
270
-
271
- describe('Error handling and edge cases', () => {
272
- test('should correctly handle non-existent routes', () => {
273
- const route: Route = router.resolve('/non-existent');
274
-
275
- expect(route.matched).toEqual([]);
276
- expect(route.config).toBeNull();
277
- expect(route.meta).toEqual({});
278
- expect(route.params).toEqual({});
279
- expect(route.path).toBe('/non-existent');
280
- });
281
-
282
- test('should correctly handle root path', () => {
283
- const route: Route = router.resolve('/');
284
-
285
- expect(route.path).toBe('/');
286
- expect(route.matched.length).toBe(1);
287
- expect(route.meta.title).toBe('Home Page');
288
- });
289
-
290
- test('should correctly handle empty string path', () => {
291
- const route: Route = router.resolve('');
292
-
293
- expect(route.path).toBe('/');
294
- expect(route.matched.length).toBe(1);
295
- });
296
-
297
- test('should correctly handle relative path', () => {
298
- const route: Route = router.resolve('about');
299
-
300
- expect(route.path).toBe('/about');
301
- expect(route.matched.length).toBe(1);
302
- });
303
-
304
- test('should correctly handle paths with special characters', () => {
305
- const route: Route = router.resolve('/user/test%20user');
306
-
307
- expect(route.params.id).toBe('test%20user');
308
- expect(route.path).toBe('/user/test%20user');
309
- });
310
-
311
- test('should correctly handle URL encoded parameters', () => {
312
- const route: Route = router.resolve('/user/john%40example.com');
313
-
314
- expect(route.params.id).toBe('john%40example.com');
315
- expect(route.path).toBe('/user/john%40example.com');
316
- });
317
- });
318
-
319
- describe('Object parameter resolution', () => {
320
- test('should correctly handle object with params', () => {
321
- const route: Route = router.resolve({
322
- path: '/user/789'
323
- });
324
-
325
- expect(route.params.id).toBe('789');
326
- expect(route.path).toBe('/user/789');
327
- });
328
-
329
- test('should correctly handle object with query', () => {
330
- const route: Route = router.resolve({
331
- path: '/about',
332
- query: { lang: 'zh', version: '2.0' }
333
- });
334
-
335
- expect(route.query.lang).toBe('zh');
336
- expect(route.query.version).toBe('2.0');
337
- expect(route.fullPath).toBe('/about?lang=zh&version=2.0');
338
- });
339
-
340
- test('should correctly handle object with hash', () => {
341
- const route: Route = router.resolve({
342
- path: '/about',
343
- hash: '#features'
344
- });
345
-
346
- expect(route.url.hash).toBe('#features');
347
- expect(route.fullPath).toBe('/about#features');
348
- });
349
-
350
- test('should correctly handle object with state', () => {
351
- const customState: Record<string, unknown> = {
352
- from: 'navigation',
353
- timestamp: 1234567890
354
- };
355
- const route: Route = router.resolve({
356
- path: '/about',
357
- state: customState
358
- });
359
-
360
- expect(route.state).toEqual(customState);
361
- });
362
-
363
- test('should correctly handle keepScrollPosition option', () => {
364
- const route: Route = router.resolve({
365
- path: '/about',
366
- keepScrollPosition: true
367
- });
368
-
369
- expect(route.keepScrollPosition).toBe(true);
370
- });
371
- });
372
-
373
- describe('URL handling', () => {
374
- test('should correctly handle complete URL', () => {
375
- const route: Route = router.resolve('http://localhost:3000/about');
376
-
377
- expect(route.path).toBe('/about');
378
- expect(route.url.href).toBe('http://localhost:3000/about');
379
- });
380
-
381
- test('should correctly handle different domain URL', () => {
382
- const route: Route = router.resolve('https://example.com/external');
383
-
384
- expect(route.matched).toEqual([]);
385
- expect(route.config).toBeNull();
386
- });
387
-
388
- test('should correctly handle URL with different port', () => {
389
- const route: Route = router.resolve('http://localhost:8080/about');
390
-
391
- expect(route.matched).toEqual([]);
392
- expect(route.config).toBeNull();
393
- });
394
- });
395
-
396
- describe('Type and status validation', () => {
397
- test('resolved route should have correct type', () => {
398
- const route: Route = router.resolve('/about');
399
-
400
- expect(route.type).toBe('push');
401
- expect(route.isPush).toBe(true);
402
- });
403
-
404
- test('resolved route should have correct handle state', () => {
405
- const route: Route = router.resolve('/about');
406
-
407
- expect(route.handle).toBe(null);
408
- });
409
-
410
- test('resolved route should have correct URL object properties', () => {
411
- const route: Route = router.resolve('/about?lang=en#intro');
412
-
413
- expect(route.url).toBeInstanceOf(URL);
414
- expect(route.url.pathname).toBe('/about');
415
- expect(route.url.search).toBe('?lang=en');
416
- expect(route.url.hash).toBe('#intro');
417
- });
418
-
419
- test('resolved route should have frozen matched array', () => {
420
- const route: Route = router.resolve('/about');
421
-
422
- expect(Object.isFrozen(route.matched)).toBe(true);
423
- });
424
- });
425
-
426
- describe('Practical use case scenarios', () => {
427
- test('should support generating link URL without triggering navigation', () => {
428
- const route: Route = router.resolve('/user/123?tab=profile');
429
- const linkUrl: string = route.url.href;
430
-
431
- expect(linkUrl).toBe('http://localhost:3000/user/123?tab=profile');
432
- expect(router.route.path).toBe('/'); // Current route unchanged
433
- });
434
-
435
- test('should support pre-checking route matching status', () => {
436
- const validRoute: Route = router.resolve('/about');
437
- const invalidRoute: Route = router.resolve('/non-existent');
438
-
439
- expect(validRoute.matched.length).toBeGreaterThan(0);
440
- expect(invalidRoute.matched.length).toBe(0);
441
- });
442
-
443
- test('should support extracting route parameters and meta information', () => {
444
- const route: Route = router.resolve('/user/123/profile');
445
-
446
- expect(route.params.id).toBe('123');
447
- expect(route.meta.section).toBe('profile');
448
- expect(route.config?.path).toBe('/profile');
449
- });
450
-
451
- test('should support testing route configuration validity with valid paths', () => {
452
- const testCases = createTestCases().validPaths;
453
-
454
- testCases.forEach(({ path, shouldMatch }) => {
455
- const route: Route = router.resolve(path);
456
- if (shouldMatch) {
457
- expect(route.matched.length).toBeGreaterThan(0);
458
- expect(route.config).not.toBeNull();
459
- }
460
- });
461
- });
462
-
463
- test('should support testing route configuration validity with invalid paths', () => {
464
- const testCases = createTestCases().invalidPaths;
465
-
466
- testCases.forEach(({ path, shouldMatch }) => {
467
- const route: Route = router.resolve(path);
468
- if (!shouldMatch) {
469
- expect(route.matched.length).toBe(0);
470
- expect(route.config).toBeNull();
471
- }
472
- });
473
- });
474
- });
475
- });