@esmx/router-vue 3.0.0-rc.84 → 3.0.0-rc.87
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.
- package/dist/plugin.mjs +18 -12
- package/dist/plugin.test.mjs +205 -3
- package/dist/router-link.mjs +14 -14
- package/dist/run-with-context.test.d.ts +1 -0
- package/dist/run-with-context.test.mjs +57 -0
- package/dist/use.d.ts +4 -10
- package/dist/use.mjs +15 -4
- package/dist/util.d.ts +12 -1
- package/dist/util.mjs +15 -1
- package/dist/util.test.d.ts +3 -0
- package/dist/util.test.mjs +228 -7
- package/package.json +3 -3
- package/src/plugin.test.ts +252 -7
- package/src/plugin.ts +18 -12
- package/src/router-link.ts +16 -15
- package/src/run-with-context.test.ts +64 -0
- package/src/use.ts +21 -17
- package/src/util.test.ts +294 -9
- package/src/util.ts +31 -1
package/dist/util.test.mjs
CHANGED
|
@@ -6,19 +6,20 @@ import { computed, nextTick, ref, version } from "vue";
|
|
|
6
6
|
import {
|
|
7
7
|
createDependentProxy,
|
|
8
8
|
createSymbolProperty,
|
|
9
|
+
defineRouterProperties,
|
|
9
10
|
isESModule,
|
|
10
|
-
|
|
11
|
+
isVue2,
|
|
11
12
|
resolveComponent
|
|
12
13
|
} from "./util.mjs";
|
|
13
14
|
describe("util.ts - Utility Functions", () => {
|
|
14
|
-
describe("
|
|
15
|
-
it("should correctly identify Vue
|
|
16
|
-
expect(
|
|
17
|
-
expect(typeof
|
|
15
|
+
describe("isVue2", () => {
|
|
16
|
+
it("should correctly identify Vue 2", () => {
|
|
17
|
+
expect(isVue2).toBe(version.startsWith("2."));
|
|
18
|
+
expect(typeof isVue2).toBe("boolean");
|
|
18
19
|
});
|
|
19
20
|
it("should be consistent with Vue version check", () => {
|
|
20
|
-
const expectedResult = version.startsWith("
|
|
21
|
-
expect(
|
|
21
|
+
const expectedResult = version.startsWith("2.");
|
|
22
|
+
expect(isVue2).toBe(expectedResult);
|
|
22
23
|
});
|
|
23
24
|
});
|
|
24
25
|
describe("createSymbolProperty", () => {
|
|
@@ -380,4 +381,224 @@ describe("util.ts - Utility Functions", () => {
|
|
|
380
381
|
expect(spy).toHaveBeenCalled();
|
|
381
382
|
});
|
|
382
383
|
});
|
|
384
|
+
describe("defineRouterProperties", () => {
|
|
385
|
+
it("should define $router and $route properties on target object", () => {
|
|
386
|
+
const target = {};
|
|
387
|
+
const mockRouter = { push: vi.fn() };
|
|
388
|
+
const mockRoute = { path: "/test" };
|
|
389
|
+
const routerGetter = vi.fn(function() {
|
|
390
|
+
return mockRouter;
|
|
391
|
+
});
|
|
392
|
+
const routeGetter = vi.fn(function() {
|
|
393
|
+
return mockRoute;
|
|
394
|
+
});
|
|
395
|
+
defineRouterProperties(target, routerGetter, routeGetter);
|
|
396
|
+
expect(target).toHaveProperty("$router");
|
|
397
|
+
expect(target).toHaveProperty("$route");
|
|
398
|
+
});
|
|
399
|
+
it("should call getter functions when accessing properties", () => {
|
|
400
|
+
const target = {};
|
|
401
|
+
const mockRouter = { push: vi.fn() };
|
|
402
|
+
const mockRoute = { path: "/test" };
|
|
403
|
+
const routerGetter = vi.fn(function() {
|
|
404
|
+
return mockRouter;
|
|
405
|
+
});
|
|
406
|
+
const routeGetter = vi.fn(function() {
|
|
407
|
+
return mockRoute;
|
|
408
|
+
});
|
|
409
|
+
defineRouterProperties(target, routerGetter, routeGetter);
|
|
410
|
+
const router = target.$router;
|
|
411
|
+
const route = target.$route;
|
|
412
|
+
expect(routerGetter).toHaveBeenCalled();
|
|
413
|
+
expect(routeGetter).toHaveBeenCalled();
|
|
414
|
+
expect(router).toBe(mockRouter);
|
|
415
|
+
expect(route).toBe(mockRoute);
|
|
416
|
+
});
|
|
417
|
+
it("should use correct this context in getter functions", () => {
|
|
418
|
+
const target = { customProp: "test" };
|
|
419
|
+
const mockRouter = { push: vi.fn() };
|
|
420
|
+
const mockRoute = { path: "/test" };
|
|
421
|
+
const routerGetter = vi.fn(function() {
|
|
422
|
+
return this.customProp ? mockRouter : {};
|
|
423
|
+
});
|
|
424
|
+
const routeGetter = vi.fn(function() {
|
|
425
|
+
return this.customProp ? mockRoute : {};
|
|
426
|
+
});
|
|
427
|
+
defineRouterProperties(target, routerGetter, routeGetter);
|
|
428
|
+
const router = target.$router;
|
|
429
|
+
const route = target.$route;
|
|
430
|
+
expect(router).toBe(mockRouter);
|
|
431
|
+
expect(route).toBe(mockRoute);
|
|
432
|
+
});
|
|
433
|
+
it("should make properties non-enumerable by default", () => {
|
|
434
|
+
const target = {};
|
|
435
|
+
const mockRouter = { push: vi.fn() };
|
|
436
|
+
const mockRoute = { path: "/test" };
|
|
437
|
+
const routerGetter = vi.fn(function() {
|
|
438
|
+
return mockRouter;
|
|
439
|
+
});
|
|
440
|
+
const routeGetter = vi.fn(function() {
|
|
441
|
+
return mockRoute;
|
|
442
|
+
});
|
|
443
|
+
defineRouterProperties(target, routerGetter, routeGetter);
|
|
444
|
+
const descriptors = Object.getOwnPropertyDescriptors(target);
|
|
445
|
+
expect(descriptors.$router.enumerable).toBe(false);
|
|
446
|
+
expect(descriptors.$route.enumerable).toBe(false);
|
|
447
|
+
});
|
|
448
|
+
it("should make properties non-configurable by default", () => {
|
|
449
|
+
const target = {};
|
|
450
|
+
const mockRouter = { push: vi.fn() };
|
|
451
|
+
const mockRoute = { path: "/test" };
|
|
452
|
+
const routerGetter = vi.fn(function() {
|
|
453
|
+
return mockRouter;
|
|
454
|
+
});
|
|
455
|
+
const routeGetter = vi.fn(function() {
|
|
456
|
+
return mockRoute;
|
|
457
|
+
});
|
|
458
|
+
defineRouterProperties(target, routerGetter, routeGetter);
|
|
459
|
+
const descriptors = Object.getOwnPropertyDescriptors(target);
|
|
460
|
+
expect(descriptors.$router.configurable).toBe(false);
|
|
461
|
+
expect(descriptors.$route.configurable).toBe(false);
|
|
462
|
+
});
|
|
463
|
+
it("should make properties configurable when configurable option is true", () => {
|
|
464
|
+
const target = {};
|
|
465
|
+
const mockRouter = { push: vi.fn() };
|
|
466
|
+
const mockRoute = { path: "/test" };
|
|
467
|
+
const routerGetter = vi.fn(function() {
|
|
468
|
+
return mockRouter;
|
|
469
|
+
});
|
|
470
|
+
const routeGetter = vi.fn(function() {
|
|
471
|
+
return mockRoute;
|
|
472
|
+
});
|
|
473
|
+
defineRouterProperties(target, routerGetter, routeGetter, true);
|
|
474
|
+
const descriptors = Object.getOwnPropertyDescriptors(target);
|
|
475
|
+
expect(descriptors.$router.configurable).toBe(true);
|
|
476
|
+
expect(descriptors.$route.configurable).toBe(true);
|
|
477
|
+
});
|
|
478
|
+
it("should define properties as getters", () => {
|
|
479
|
+
const target = {};
|
|
480
|
+
const mockRouter = { push: vi.fn() };
|
|
481
|
+
const mockRoute = { path: "/test" };
|
|
482
|
+
const routerGetter = vi.fn(function() {
|
|
483
|
+
return mockRouter;
|
|
484
|
+
});
|
|
485
|
+
const routeGetter = vi.fn(function() {
|
|
486
|
+
return mockRoute;
|
|
487
|
+
});
|
|
488
|
+
defineRouterProperties(target, routerGetter, routeGetter);
|
|
489
|
+
const descriptors = Object.getOwnPropertyDescriptors(target);
|
|
490
|
+
expect(typeof descriptors.$router.get).toBe("function");
|
|
491
|
+
expect(typeof descriptors.$route.get).toBe("function");
|
|
492
|
+
expect(descriptors.$router.set).toBeUndefined();
|
|
493
|
+
expect(descriptors.$route.set).toBeUndefined();
|
|
494
|
+
});
|
|
495
|
+
it("should call getter each time property is accessed", () => {
|
|
496
|
+
const target = {};
|
|
497
|
+
const mockRouter = { push: vi.fn() };
|
|
498
|
+
const routerGetter = vi.fn(function() {
|
|
499
|
+
return mockRouter;
|
|
500
|
+
});
|
|
501
|
+
const routeGetter = vi.fn(function() {
|
|
502
|
+
return { path: "/test" };
|
|
503
|
+
});
|
|
504
|
+
defineRouterProperties(target, routerGetter, routeGetter);
|
|
505
|
+
target.$router;
|
|
506
|
+
target.$router;
|
|
507
|
+
target.$router;
|
|
508
|
+
expect(routerGetter).toHaveBeenCalledTimes(3);
|
|
509
|
+
});
|
|
510
|
+
it("should work with different target objects", () => {
|
|
511
|
+
const targets = [
|
|
512
|
+
{},
|
|
513
|
+
{ existingProp: "value" },
|
|
514
|
+
/* @__PURE__ */ Object.create(null),
|
|
515
|
+
new class Test {
|
|
516
|
+
}()
|
|
517
|
+
];
|
|
518
|
+
const mockRouter = { push: vi.fn() };
|
|
519
|
+
const mockRoute = { path: "/test" };
|
|
520
|
+
const routerGetter = vi.fn(function() {
|
|
521
|
+
return mockRouter;
|
|
522
|
+
});
|
|
523
|
+
const routeGetter = vi.fn(function() {
|
|
524
|
+
return mockRoute;
|
|
525
|
+
});
|
|
526
|
+
targets.forEach((target) => {
|
|
527
|
+
defineRouterProperties(target, routerGetter, routeGetter);
|
|
528
|
+
expect(target).toHaveProperty("$router");
|
|
529
|
+
expect(target).toHaveProperty("$route");
|
|
530
|
+
const router = target.$router;
|
|
531
|
+
const route = target.$route;
|
|
532
|
+
expect(router).toBe(mockRouter);
|
|
533
|
+
expect(route).toBe(mockRoute);
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
it("should preserve existing properties on target object", () => {
|
|
537
|
+
const target = {
|
|
538
|
+
existingProp: "value",
|
|
539
|
+
$existingRouter: "should not be affected"
|
|
540
|
+
};
|
|
541
|
+
const mockRouter = { push: vi.fn() };
|
|
542
|
+
const mockRoute = { path: "/test" };
|
|
543
|
+
const routerGetter = vi.fn(function() {
|
|
544
|
+
return mockRouter;
|
|
545
|
+
});
|
|
546
|
+
const routeGetter = vi.fn(function() {
|
|
547
|
+
return mockRoute;
|
|
548
|
+
});
|
|
549
|
+
defineRouterProperties(target, routerGetter, routeGetter);
|
|
550
|
+
expect(target.existingProp).toBe("value");
|
|
551
|
+
expect(target.$existingRouter).toBe("should not be affected");
|
|
552
|
+
expect(target).toHaveProperty("$router");
|
|
553
|
+
expect(target).toHaveProperty("$route");
|
|
554
|
+
});
|
|
555
|
+
it("should handle getter functions that return undefined", () => {
|
|
556
|
+
const target = {};
|
|
557
|
+
const routerGetter = vi.fn(function() {
|
|
558
|
+
return void 0;
|
|
559
|
+
});
|
|
560
|
+
const routeGetter = vi.fn(function() {
|
|
561
|
+
return void 0;
|
|
562
|
+
});
|
|
563
|
+
defineRouterProperties(target, routerGetter, routeGetter);
|
|
564
|
+
const router = target.$router;
|
|
565
|
+
const route = target.$route;
|
|
566
|
+
expect(router).toBeUndefined();
|
|
567
|
+
expect(route).toBeUndefined();
|
|
568
|
+
expect(routerGetter).toHaveBeenCalled();
|
|
569
|
+
expect(routeGetter).toHaveBeenCalled();
|
|
570
|
+
});
|
|
571
|
+
it("should handle getter functions that throw errors", () => {
|
|
572
|
+
const target = {};
|
|
573
|
+
const routerGetter = vi.fn(function() {
|
|
574
|
+
throw new Error("Router error");
|
|
575
|
+
});
|
|
576
|
+
const routeGetter = vi.fn(function() {
|
|
577
|
+
throw new Error("Route error");
|
|
578
|
+
});
|
|
579
|
+
defineRouterProperties(target, routerGetter, routeGetter);
|
|
580
|
+
expect(() => target.$router).toThrow("Router error");
|
|
581
|
+
expect(() => target.$route).toThrow("Route error");
|
|
582
|
+
});
|
|
583
|
+
it("should work with arrow functions as getters", () => {
|
|
584
|
+
const target = {};
|
|
585
|
+
const mockRouter = { push: vi.fn() };
|
|
586
|
+
const mockRoute = { path: "/test" };
|
|
587
|
+
const context = { customContext: "test" };
|
|
588
|
+
const routerGetter = vi.fn(() => mockRouter);
|
|
589
|
+
const routeGetter = vi.fn(() => mockRoute);
|
|
590
|
+
defineRouterProperties.call(
|
|
591
|
+
context,
|
|
592
|
+
target,
|
|
593
|
+
routerGetter,
|
|
594
|
+
routeGetter
|
|
595
|
+
);
|
|
596
|
+
const router = target.$router;
|
|
597
|
+
const route = target.$route;
|
|
598
|
+
expect(router).toBe(mockRouter);
|
|
599
|
+
expect(route).toBe(mockRoute);
|
|
600
|
+
expect(routerGetter).toHaveBeenCalled();
|
|
601
|
+
expect(routeGetter).toHaveBeenCalled();
|
|
602
|
+
});
|
|
603
|
+
});
|
|
383
604
|
});
|
package/package.json
CHANGED
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"vue": "^3.5.0 || ^2.7.0"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@esmx/router": "3.0.0-rc.
|
|
53
|
+
"@esmx/router": "3.0.0-rc.87"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@biomejs/biome": "2.3.7",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"vue": "3.5.23",
|
|
63
63
|
"vue2": "npm:vue@2.7.16"
|
|
64
64
|
},
|
|
65
|
-
"version": "3.0.0-rc.
|
|
65
|
+
"version": "3.0.0-rc.87",
|
|
66
66
|
"type": "module",
|
|
67
67
|
"private": false,
|
|
68
68
|
"exports": {
|
|
@@ -81,5 +81,5 @@
|
|
|
81
81
|
"template",
|
|
82
82
|
"public"
|
|
83
83
|
],
|
|
84
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "1f79a73438c2193fd06ebaa3dc6a4ec420e6b026"
|
|
85
85
|
}
|
package/src/plugin.test.ts
CHANGED
|
@@ -155,9 +155,8 @@ describe('plugin.ts - RouterPlugin', () => {
|
|
|
155
155
|
expect(routeDescriptor?.get).toBeDefined();
|
|
156
156
|
expect(typeof routeDescriptor?.get).toBe('function');
|
|
157
157
|
|
|
158
|
-
// Verify the descriptor is properly configured for reactivity
|
|
159
158
|
expect(routeDescriptor?.enumerable).toBe(false);
|
|
160
|
-
expect(routeDescriptor?.configurable).toBe(
|
|
159
|
+
expect(routeDescriptor?.configurable).toBe(true);
|
|
161
160
|
});
|
|
162
161
|
|
|
163
162
|
it('should provide consistent $router instance across components', async () => {
|
|
@@ -481,6 +480,253 @@ describe('plugin.ts - RouterPlugin', () => {
|
|
|
481
480
|
});
|
|
482
481
|
});
|
|
483
482
|
|
|
483
|
+
describe('$router and $route Access', () => {
|
|
484
|
+
it('should throw error when accessing $router without useProvideRouter', () => {
|
|
485
|
+
app = createApp({
|
|
486
|
+
render: () => h('div', 'Test App')
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
app.use(RouterPlugin);
|
|
490
|
+
|
|
491
|
+
const globalProperties = app.config.globalProperties;
|
|
492
|
+
expect(() => {
|
|
493
|
+
(globalProperties as any).$router;
|
|
494
|
+
}).toThrow(
|
|
495
|
+
'[@esmx/router-vue] Router not provided. Please call useProvideRouter() in your root component setup.'
|
|
496
|
+
);
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it('should throw error when accessing $route without useProvideRouter', () => {
|
|
500
|
+
app = createApp({
|
|
501
|
+
render: () => h('div', 'Test App')
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
app.use(RouterPlugin);
|
|
505
|
+
|
|
506
|
+
const globalProperties = app.config.globalProperties;
|
|
507
|
+
expect(() => {
|
|
508
|
+
(globalProperties as any).$route;
|
|
509
|
+
}).toThrow(
|
|
510
|
+
'[@esmx/router-vue] Router not provided. Please call useProvideRouter() in your root component setup.'
|
|
511
|
+
);
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
it('should override default getters after useProvideRouter is called', async () => {
|
|
515
|
+
app = createApp({
|
|
516
|
+
setup() {
|
|
517
|
+
useProvideRouter(router);
|
|
518
|
+
return () => h('div', 'Test App');
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
app.use(RouterPlugin);
|
|
523
|
+
app.mount(container);
|
|
524
|
+
await nextTick();
|
|
525
|
+
|
|
526
|
+
const globalProperties = app.config.globalProperties;
|
|
527
|
+
expect(() => {
|
|
528
|
+
(globalProperties as any).$router;
|
|
529
|
+
}).not.toThrow();
|
|
530
|
+
expect(() => {
|
|
531
|
+
(globalProperties as any).$route;
|
|
532
|
+
}).not.toThrow();
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
it('should return correct router instance via $router', async () => {
|
|
536
|
+
let capturedRouter: Router | null = null;
|
|
537
|
+
|
|
538
|
+
const TestComponent = defineComponent({
|
|
539
|
+
mounted() {
|
|
540
|
+
capturedRouter = this.$router;
|
|
541
|
+
},
|
|
542
|
+
render() {
|
|
543
|
+
return h('div', 'Test');
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
app = createApp({
|
|
548
|
+
setup() {
|
|
549
|
+
useProvideRouter(router);
|
|
550
|
+
return () => h(TestComponent);
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
app.use(RouterPlugin);
|
|
555
|
+
app.mount(container);
|
|
556
|
+
await nextTick();
|
|
557
|
+
|
|
558
|
+
expect(capturedRouter).toBeDefined();
|
|
559
|
+
expect(capturedRouter).toBeInstanceOf(Router);
|
|
560
|
+
expect((capturedRouter as unknown as Router).route.path).toBe('/');
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
it('should return correct route via $route', async () => {
|
|
564
|
+
let capturedRoute: Route | null = null;
|
|
565
|
+
|
|
566
|
+
const TestComponent = defineComponent({
|
|
567
|
+
mounted() {
|
|
568
|
+
capturedRoute = this.$route;
|
|
569
|
+
},
|
|
570
|
+
render() {
|
|
571
|
+
return h('div', 'Test');
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
app = createApp({
|
|
576
|
+
setup() {
|
|
577
|
+
useProvideRouter(router);
|
|
578
|
+
return () => h(TestComponent);
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
app.use(RouterPlugin);
|
|
583
|
+
app.mount(container);
|
|
584
|
+
await nextTick();
|
|
585
|
+
|
|
586
|
+
expect(capturedRoute).toBeDefined();
|
|
587
|
+
expect((capturedRoute as unknown as Route).path).toBe('/');
|
|
588
|
+
expect((capturedRoute as unknown as Route).meta?.title).toBe(
|
|
589
|
+
'Home'
|
|
590
|
+
);
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
it('should update $route when navigation occurs', async () => {
|
|
594
|
+
const routes: string[] = [];
|
|
595
|
+
|
|
596
|
+
const TestComponent = defineComponent({
|
|
597
|
+
mounted() {
|
|
598
|
+
routes.push(this.$route.path);
|
|
599
|
+
},
|
|
600
|
+
updated() {
|
|
601
|
+
routes.push(this.$route.path);
|
|
602
|
+
},
|
|
603
|
+
render() {
|
|
604
|
+
return h('div', this.$route.path);
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
app = createApp({
|
|
609
|
+
setup() {
|
|
610
|
+
useProvideRouter(router);
|
|
611
|
+
return () => h(TestComponent);
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
app.use(RouterPlugin);
|
|
616
|
+
app.mount(container);
|
|
617
|
+
await nextTick();
|
|
618
|
+
|
|
619
|
+
expect(routes).toContain('/');
|
|
620
|
+
|
|
621
|
+
await router.push('/about');
|
|
622
|
+
await nextTick();
|
|
623
|
+
|
|
624
|
+
expect(router.route.path).toBe('/about');
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
it('should provide same $router instance in nested components', async () => {
|
|
628
|
+
const routerInstances: Router[] = [];
|
|
629
|
+
|
|
630
|
+
const ChildComponent = defineComponent({
|
|
631
|
+
mounted() {
|
|
632
|
+
routerInstances.push(this.$router);
|
|
633
|
+
},
|
|
634
|
+
render() {
|
|
635
|
+
return h('div', 'Child');
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
const ParentComponent = defineComponent({
|
|
640
|
+
mounted() {
|
|
641
|
+
routerInstances.push(this.$router);
|
|
642
|
+
},
|
|
643
|
+
render() {
|
|
644
|
+
return h('div', [h('span', 'Parent'), h(ChildComponent)]);
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
app = createApp({
|
|
649
|
+
setup() {
|
|
650
|
+
useProvideRouter(router);
|
|
651
|
+
return () => h(ParentComponent);
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
app.use(RouterPlugin);
|
|
656
|
+
app.mount(container);
|
|
657
|
+
await nextTick();
|
|
658
|
+
|
|
659
|
+
expect(routerInstances.length).toBe(2);
|
|
660
|
+
expect(routerInstances[0]).toBe(routerInstances[1]);
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
it('should allow navigation via $router.push', async () => {
|
|
664
|
+
let capturedRouter: Router | null = null;
|
|
665
|
+
|
|
666
|
+
const TestComponent = defineComponent({
|
|
667
|
+
mounted() {
|
|
668
|
+
capturedRouter = this.$router;
|
|
669
|
+
},
|
|
670
|
+
render() {
|
|
671
|
+
return h('div', 'Test');
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
app = createApp({
|
|
676
|
+
setup() {
|
|
677
|
+
useProvideRouter(router);
|
|
678
|
+
return () => h(TestComponent);
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
app.use(RouterPlugin);
|
|
683
|
+
app.mount(container);
|
|
684
|
+
await nextTick();
|
|
685
|
+
|
|
686
|
+
expect(capturedRouter).toBeDefined();
|
|
687
|
+
const routerInstance = capturedRouter as unknown as Router;
|
|
688
|
+
expect(typeof routerInstance.push).toBe('function');
|
|
689
|
+
|
|
690
|
+
await routerInstance.push('/about');
|
|
691
|
+
await nextTick();
|
|
692
|
+
|
|
693
|
+
expect(router.route.path).toBe('/about');
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
it('should allow navigation via $router.replace', async () => {
|
|
697
|
+
let capturedRouter: Router | null = null;
|
|
698
|
+
|
|
699
|
+
const TestComponent = defineComponent({
|
|
700
|
+
mounted() {
|
|
701
|
+
capturedRouter = this.$router;
|
|
702
|
+
},
|
|
703
|
+
render() {
|
|
704
|
+
return h('div', 'Test');
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
app = createApp({
|
|
709
|
+
setup() {
|
|
710
|
+
useProvideRouter(router);
|
|
711
|
+
return () => h(TestComponent);
|
|
712
|
+
}
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
app.use(RouterPlugin);
|
|
716
|
+
app.mount(container);
|
|
717
|
+
await nextTick();
|
|
718
|
+
|
|
719
|
+
expect(capturedRouter).toBeDefined();
|
|
720
|
+
const routerInstance = capturedRouter as unknown as Router;
|
|
721
|
+
expect(typeof routerInstance.replace).toBe('function');
|
|
722
|
+
|
|
723
|
+
await routerInstance.replace('/about');
|
|
724
|
+
await nextTick();
|
|
725
|
+
|
|
726
|
+
expect(router.route.path).toBe('/about');
|
|
727
|
+
});
|
|
728
|
+
});
|
|
729
|
+
|
|
484
730
|
describe('Advanced Plugin Features', () => {
|
|
485
731
|
it('should support property descriptor configuration', () => {
|
|
486
732
|
interface TestApp {
|
|
@@ -516,14 +762,13 @@ describe('plugin.ts - RouterPlugin', () => {
|
|
|
516
762
|
'$route'
|
|
517
763
|
);
|
|
518
764
|
|
|
519
|
-
// Check descriptor properties - Object.defineProperties sets these to false by default
|
|
520
765
|
expect(routerDescriptor?.get).toBeDefined();
|
|
521
|
-
expect(routerDescriptor?.enumerable).toBe(false);
|
|
522
|
-
expect(routerDescriptor?.configurable).toBe(
|
|
766
|
+
expect(routerDescriptor?.enumerable).toBe(false);
|
|
767
|
+
expect(routerDescriptor?.configurable).toBe(true);
|
|
523
768
|
|
|
524
769
|
expect(routeDescriptor?.get).toBeDefined();
|
|
525
|
-
expect(routeDescriptor?.enumerable).toBe(false);
|
|
526
|
-
expect(routeDescriptor?.configurable).toBe(
|
|
770
|
+
expect(routeDescriptor?.enumerable).toBe(false);
|
|
771
|
+
expect(routeDescriptor?.configurable).toBe(true);
|
|
527
772
|
});
|
|
528
773
|
|
|
529
774
|
it('should handle different app instance structures', () => {
|
package/src/plugin.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RouterLink } from './router-link';
|
|
2
2
|
import { RouterView } from './router-view';
|
|
3
3
|
import { getRoute, getRouter } from './use';
|
|
4
|
-
import {
|
|
4
|
+
import { defineRouterProperties, isVue2 } from './util';
|
|
5
5
|
|
|
6
6
|
interface VueApp {
|
|
7
7
|
config?: {
|
|
@@ -81,18 +81,24 @@ export const RouterPlugin = {
|
|
|
81
81
|
if (!target) {
|
|
82
82
|
throw new Error('[@esmx/router-vue] Invalid Vue app instance');
|
|
83
83
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
if (isVue2) {
|
|
85
|
+
defineRouterProperties(
|
|
86
|
+
target,
|
|
87
|
+
function (this: any) {
|
|
88
|
+
return getRouter(this);
|
|
89
|
+
},
|
|
90
|
+
function (this: any) {
|
|
91
|
+
return getRoute(this);
|
|
88
92
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
);
|
|
94
|
+
} else {
|
|
95
|
+
const throwError = () => {
|
|
96
|
+
throw new Error(
|
|
97
|
+
'[@esmx/router-vue] Router not provided. Please call useProvideRouter() in your root component setup.'
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
defineRouterProperties(target, throwError, throwError, true);
|
|
101
|
+
}
|
|
96
102
|
|
|
97
103
|
// Register global components
|
|
98
104
|
vueApp.component('RouterLink', RouterLink);
|
package/src/router-link.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RouterLinkProps } from '@esmx/router';
|
|
2
2
|
import { defineComponent, h, type PropType } from 'vue';
|
|
3
3
|
import { useLink } from './use';
|
|
4
|
-
import {
|
|
4
|
+
import { isVue2 } from './util';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* RouterLink component for navigation.
|
|
@@ -136,33 +136,34 @@ export const RouterLink = defineComponent({
|
|
|
136
136
|
setup(props, context) {
|
|
137
137
|
const link = useLink(props);
|
|
138
138
|
|
|
139
|
-
if (
|
|
139
|
+
if (isVue2) {
|
|
140
140
|
return () => {
|
|
141
|
+
const { class: className, ...attributes } =
|
|
142
|
+
link.value.attributes;
|
|
141
143
|
return h(
|
|
142
144
|
link.value.tag,
|
|
143
145
|
{
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
)
|
|
146
|
+
attrs: {
|
|
147
|
+
...attributes,
|
|
148
|
+
...context.attrs
|
|
149
|
+
},
|
|
150
|
+
class: className,
|
|
151
|
+
on: link.value.createEventHandlers()
|
|
150
152
|
},
|
|
151
153
|
context.slots.default?.()
|
|
152
154
|
);
|
|
153
155
|
};
|
|
154
156
|
}
|
|
155
157
|
return () => {
|
|
156
|
-
const { class: className, ...attributes } = link.value.attributes;
|
|
157
158
|
return h(
|
|
158
159
|
link.value.tag,
|
|
159
160
|
{
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
161
|
+
...link.value.attributes,
|
|
162
|
+
...context.attrs,
|
|
163
|
+
...link.value.createEventHandlers(
|
|
164
|
+
(name) =>
|
|
165
|
+
`on${name.charAt(0).toUpperCase()}${name.slice(1)}`
|
|
166
|
+
)
|
|
166
167
|
},
|
|
167
168
|
context.slots.default?.()
|
|
168
169
|
);
|