@esmx/router-vue 3.0.0-rc.103
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/LICENSE +21 -0
- package/README.md +570 -0
- package/README.zh-CN.md +570 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.mjs +13 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.mjs +216 -0
- package/dist/plugin.d.ts +61 -0
- package/dist/plugin.mjs +41 -0
- package/dist/plugin.test.d.ts +1 -0
- package/dist/plugin.test.mjs +631 -0
- package/dist/router-link.d.ts +220 -0
- package/dist/router-link.mjs +119 -0
- package/dist/router-link.test.d.ts +1 -0
- package/dist/router-link.test.mjs +663 -0
- package/dist/router-view.d.ts +31 -0
- package/dist/router-view.mjs +15 -0
- package/dist/router-view.test.d.ts +1 -0
- package/dist/router-view.test.mjs +676 -0
- package/dist/run-with-context.test.d.ts +1 -0
- package/dist/run-with-context.test.mjs +57 -0
- package/dist/use.d.ts +260 -0
- package/dist/use.mjs +125 -0
- package/dist/use.test.d.ts +1 -0
- package/dist/use.test.mjs +381 -0
- package/dist/util.d.ts +20 -0
- package/dist/util.mjs +49 -0
- package/dist/util.test.d.ts +4 -0
- package/dist/util.test.mjs +604 -0
- package/dist/vue2.d.ts +15 -0
- package/dist/vue2.mjs +0 -0
- package/dist/vue3.d.ts +13 -0
- package/dist/vue3.mjs +0 -0
- package/package.json +85 -0
- package/src/index.test.ts +273 -0
- package/src/index.ts +15 -0
- package/src/plugin.test.ts +812 -0
- package/src/plugin.ts +107 -0
- package/src/router-link.test.ts +830 -0
- package/src/router-link.ts +172 -0
- package/src/router-view.test.ts +840 -0
- package/src/router-view.ts +59 -0
- package/src/run-with-context.test.ts +64 -0
- package/src/use.test.ts +484 -0
- package/src/use.ts +416 -0
- package/src/util.test.ts +760 -0
- package/src/util.ts +85 -0
- package/src/vue2.ts +18 -0
- package/src/vue3.ts +15 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { defineComponent, h } from 'vue';
|
|
2
|
+
import { _useRouterViewDepth, useRoute } from './use';
|
|
3
|
+
import { resolveComponent } from './util';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* RouterView component for rendering matched route components.
|
|
7
|
+
* Acts as a placeholder where route components are rendered based on the current route.
|
|
8
|
+
* Supports nested routing with proper depth tracking using Vue's provide/inject mechanism.
|
|
9
|
+
*
|
|
10
|
+
* @param props - Component properties (RouterView accepts no props)
|
|
11
|
+
* @param context - Vue setup context (not used)
|
|
12
|
+
* @param context.slots - Component slots (not used)
|
|
13
|
+
* @returns Vue render function that renders the matched route component at current depth
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
*
|
|
17
|
+
* ```vue
|
|
18
|
+
* <template>
|
|
19
|
+
* <div id="app">
|
|
20
|
+
* <!-- Navigation links -->
|
|
21
|
+
* <nav>
|
|
22
|
+
* <RouterLink to="/">Home</RouterLink>
|
|
23
|
+
* <RouterLink to="/about">About</RouterLink>
|
|
24
|
+
* <RouterLink to="/users">Users</RouterLink>
|
|
25
|
+
* </nav>
|
|
26
|
+
*
|
|
27
|
+
* <!-- Root level route components render here -->
|
|
28
|
+
* <RouterView />
|
|
29
|
+
* </div>
|
|
30
|
+
* </template>
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export const RouterView = defineComponent({
|
|
34
|
+
name: 'RouterView',
|
|
35
|
+
setup() {
|
|
36
|
+
const route = useRoute();
|
|
37
|
+
|
|
38
|
+
// Get current RouterView depth and automatically provide depth + 1 for children
|
|
39
|
+
// This enables proper nested routing by tracking how deep we are in the component tree
|
|
40
|
+
const depth = _useRouterViewDepth(true);
|
|
41
|
+
|
|
42
|
+
return () => {
|
|
43
|
+
// Get the matched route configuration at current depth
|
|
44
|
+
// route.matched is an array of matched route configs from parent to child
|
|
45
|
+
const matchedRoute = route.matched[depth];
|
|
46
|
+
|
|
47
|
+
// Resolve the component, handling ES module format if necessary
|
|
48
|
+
const component = matchedRoute
|
|
49
|
+
? resolveComponent(matchedRoute.component)
|
|
50
|
+
: null;
|
|
51
|
+
|
|
52
|
+
// Render the component with compilePath as key to force re-render when route config changes
|
|
53
|
+
// Using compilePath ensures component is recreated when navigating to different route configs
|
|
54
|
+
return component
|
|
55
|
+
? h(component, { key: matchedRoute.compilePath })
|
|
56
|
+
: null;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment happy-dom
|
|
3
|
+
*/
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import type { InjectionKey } from 'vue';
|
|
6
|
+
import {
|
|
7
|
+
createApp,
|
|
8
|
+
getCurrentInstance,
|
|
9
|
+
h,
|
|
10
|
+
inject,
|
|
11
|
+
nextTick,
|
|
12
|
+
provide
|
|
13
|
+
} from 'vue';
|
|
14
|
+
|
|
15
|
+
describe('app.runWithContext()', () => {
|
|
16
|
+
it('should exist on Vue app', () => {
|
|
17
|
+
const app = createApp({ render: () => h('div') });
|
|
18
|
+
expect(typeof app.runWithContext).toBe('function');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should enable inject to read provided value within context', () => {
|
|
22
|
+
const KEY: InjectionKey<number> = Symbol('ctx-key');
|
|
23
|
+
const app = createApp({ render: () => h('div') });
|
|
24
|
+
app.provide(KEY, 42);
|
|
25
|
+
|
|
26
|
+
const value = app.runWithContext(() => inject(KEY));
|
|
27
|
+
expect(value).toBe(42);
|
|
28
|
+
});
|
|
29
|
+
it('should not read value provided in root setup via runWithContext', async () => {
|
|
30
|
+
const KEY: InjectionKey<number> = Symbol('ctx-key-setup');
|
|
31
|
+
const app = createApp({
|
|
32
|
+
setup() {
|
|
33
|
+
provide(KEY, 7);
|
|
34
|
+
return () => h('div');
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const container = document.createElement('div');
|
|
38
|
+
document.body.appendChild(container);
|
|
39
|
+
app.mount(container);
|
|
40
|
+
await nextTick();
|
|
41
|
+
const value = app.runWithContext(() => inject(KEY));
|
|
42
|
+
expect(value).toBeUndefined();
|
|
43
|
+
app.unmount();
|
|
44
|
+
container.remove();
|
|
45
|
+
});
|
|
46
|
+
it('should read app-level provide set inside setup via appContext', async () => {
|
|
47
|
+
const KEY: InjectionKey<number> = Symbol('ctx-key-setup-app');
|
|
48
|
+
const app = createApp({
|
|
49
|
+
setup() {
|
|
50
|
+
const appInst = getCurrentInstance()!.appContext.app;
|
|
51
|
+
appInst.provide(KEY, 9);
|
|
52
|
+
return () => h('div');
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
const container = document.createElement('div');
|
|
56
|
+
document.body.appendChild(container);
|
|
57
|
+
app.mount(container);
|
|
58
|
+
await nextTick();
|
|
59
|
+
const value = app.runWithContext(() => inject(KEY));
|
|
60
|
+
expect(value).toBe(9);
|
|
61
|
+
app.unmount();
|
|
62
|
+
container.remove();
|
|
63
|
+
});
|
|
64
|
+
});
|
package/src/use.test.ts
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
import { type Route, Router, RouterMode } from '@esmx/router';
|
|
2
|
+
/**
|
|
3
|
+
* @vitest-environment happy-dom
|
|
4
|
+
*/
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
6
|
+
import {
|
|
7
|
+
createApp,
|
|
8
|
+
defineComponent,
|
|
9
|
+
getCurrentInstance,
|
|
10
|
+
h,
|
|
11
|
+
nextTick
|
|
12
|
+
} from 'vue';
|
|
13
|
+
import { RouterView } from './router-view';
|
|
14
|
+
import {
|
|
15
|
+
getRouterViewDepth,
|
|
16
|
+
useProvideRouter,
|
|
17
|
+
useRoute,
|
|
18
|
+
useRouter,
|
|
19
|
+
useRouterViewDepth
|
|
20
|
+
} from './use';
|
|
21
|
+
|
|
22
|
+
describe('Router Vue Integration', () => {
|
|
23
|
+
let app: ReturnType<typeof createApp>;
|
|
24
|
+
let router: Router;
|
|
25
|
+
let mountPoint: HTMLElement;
|
|
26
|
+
|
|
27
|
+
beforeEach(async () => {
|
|
28
|
+
// Create a real Router instance
|
|
29
|
+
router = new Router({
|
|
30
|
+
mode: RouterMode.memory,
|
|
31
|
+
routes: [
|
|
32
|
+
{ path: '/initial', component: {} },
|
|
33
|
+
{ path: '/new-route', component: {} },
|
|
34
|
+
{ path: '/user/:id', component: {} },
|
|
35
|
+
{ path: '/new-path', component: {} }
|
|
36
|
+
],
|
|
37
|
+
base: new URL('http://localhost:8000/')
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Ensure navigation to initial route is complete
|
|
41
|
+
await router.replace('/initial');
|
|
42
|
+
|
|
43
|
+
// Create mount point
|
|
44
|
+
mountPoint = document.createElement('div');
|
|
45
|
+
mountPoint.id = 'app';
|
|
46
|
+
document.body.appendChild(mountPoint);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
afterEach(() => {
|
|
50
|
+
if (app) {
|
|
51
|
+
app.unmount();
|
|
52
|
+
}
|
|
53
|
+
document.body.removeChild(mountPoint);
|
|
54
|
+
|
|
55
|
+
// Clean up router
|
|
56
|
+
router.destroy();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('Router and Route Access', () => {
|
|
60
|
+
it('should provide router and route access', async () => {
|
|
61
|
+
let routerResult: Router | undefined;
|
|
62
|
+
let routeResult: Route | undefined;
|
|
63
|
+
|
|
64
|
+
const TestApp = {
|
|
65
|
+
setup() {
|
|
66
|
+
useProvideRouter(router);
|
|
67
|
+
routerResult = useRouter();
|
|
68
|
+
routeResult = useRoute();
|
|
69
|
+
return () => h('div', 'Test App');
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
app = createApp(TestApp);
|
|
74
|
+
app.mount('#app');
|
|
75
|
+
|
|
76
|
+
// Check retrieved objects
|
|
77
|
+
expect(routerResult).toEqual(router);
|
|
78
|
+
expect(routeResult).toBeDefined();
|
|
79
|
+
expect(routeResult?.path).toBe('/initial');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('Route Reactivity', () => {
|
|
84
|
+
it('should update route properties when route changes', async () => {
|
|
85
|
+
let routeRef: Route | undefined;
|
|
86
|
+
|
|
87
|
+
const TestApp = {
|
|
88
|
+
setup() {
|
|
89
|
+
useProvideRouter(router);
|
|
90
|
+
routeRef = useRoute();
|
|
91
|
+
return () => h('div', routeRef?.path);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
app = createApp(TestApp);
|
|
96
|
+
app.mount('#app');
|
|
97
|
+
|
|
98
|
+
// Initial state
|
|
99
|
+
expect(routeRef?.path).toBe('/initial');
|
|
100
|
+
|
|
101
|
+
// Save reference to check identity
|
|
102
|
+
const initialRouteRef = routeRef;
|
|
103
|
+
|
|
104
|
+
// Navigate to new route
|
|
105
|
+
await router.replace('/new-route');
|
|
106
|
+
await nextTick();
|
|
107
|
+
|
|
108
|
+
// Check that reference is preserved but properties are updated
|
|
109
|
+
expect(routeRef).toBe(initialRouteRef);
|
|
110
|
+
expect(routeRef?.path).toBe('/new-route');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should update route params when route changes', async () => {
|
|
114
|
+
let routeRef: Route | undefined;
|
|
115
|
+
|
|
116
|
+
const TestApp = {
|
|
117
|
+
setup() {
|
|
118
|
+
useProvideRouter(router);
|
|
119
|
+
routeRef = useRoute();
|
|
120
|
+
return () =>
|
|
121
|
+
h('div', [
|
|
122
|
+
h('span', routeRef?.path),
|
|
123
|
+
h('span', routeRef?.params?.id || 'no-id')
|
|
124
|
+
]);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
app = createApp(TestApp);
|
|
129
|
+
app.mount('#app');
|
|
130
|
+
|
|
131
|
+
// Navigate to route with params
|
|
132
|
+
await router.replace('/user/123');
|
|
133
|
+
await nextTick();
|
|
134
|
+
|
|
135
|
+
// Check if params are updated
|
|
136
|
+
expect(routeRef?.path).toBe('/user/123');
|
|
137
|
+
expect(routeRef?.params?.id).toBe('123');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should automatically update view when route changes', async () => {
|
|
141
|
+
// Track render count
|
|
142
|
+
const renderCount = { value: 0 };
|
|
143
|
+
let routeRef: Route | undefined;
|
|
144
|
+
|
|
145
|
+
const TestApp = {
|
|
146
|
+
setup() {
|
|
147
|
+
useProvideRouter(router);
|
|
148
|
+
routeRef = useRoute();
|
|
149
|
+
return () => {
|
|
150
|
+
renderCount.value++;
|
|
151
|
+
return h('div', routeRef?.path);
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
app = createApp(TestApp);
|
|
157
|
+
app.mount('#app');
|
|
158
|
+
|
|
159
|
+
// Initial render
|
|
160
|
+
const initialRenderCount = renderCount.value;
|
|
161
|
+
expect(routeRef?.path).toBe('/initial');
|
|
162
|
+
|
|
163
|
+
// Navigate to new route
|
|
164
|
+
await router.replace('/new-route');
|
|
165
|
+
await nextTick();
|
|
166
|
+
|
|
167
|
+
// Check if render count increased, confirming view update
|
|
168
|
+
expect(renderCount.value).toBeGreaterThan(initialRenderCount);
|
|
169
|
+
expect(routeRef?.path).toBe('/new-route');
|
|
170
|
+
|
|
171
|
+
// Navigate to another route
|
|
172
|
+
const previousRenderCount = renderCount.value;
|
|
173
|
+
await router.replace('/new-path');
|
|
174
|
+
await nextTick();
|
|
175
|
+
|
|
176
|
+
// Check if render count increased again
|
|
177
|
+
expect(renderCount.value).toBeGreaterThan(previousRenderCount);
|
|
178
|
+
expect(routeRef?.path).toBe('/new-path');
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
describe('Nested Components', () => {
|
|
183
|
+
it('should provide route context to child components', async () => {
|
|
184
|
+
let parentRoute: Route | undefined;
|
|
185
|
+
let childRoute: Route | undefined;
|
|
186
|
+
|
|
187
|
+
const ChildComponent = {
|
|
188
|
+
setup() {
|
|
189
|
+
childRoute = useRoute();
|
|
190
|
+
return () => h('div', 'Child: ' + childRoute?.path);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const ParentComponent = {
|
|
195
|
+
setup() {
|
|
196
|
+
parentRoute = useRoute();
|
|
197
|
+
return () =>
|
|
198
|
+
h('div', [
|
|
199
|
+
h('span', 'Parent: ' + parentRoute?.path),
|
|
200
|
+
h(ChildComponent)
|
|
201
|
+
]);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const TestApp = {
|
|
206
|
+
setup() {
|
|
207
|
+
useProvideRouter(router);
|
|
208
|
+
return () => h(ParentComponent);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
app = createApp(TestApp);
|
|
213
|
+
app.mount('#app');
|
|
214
|
+
|
|
215
|
+
expect(parentRoute).toBeDefined();
|
|
216
|
+
expect(childRoute).toBeDefined();
|
|
217
|
+
expect(parentRoute?.path).toBe('/initial');
|
|
218
|
+
expect(childRoute?.path).toBe('/initial');
|
|
219
|
+
|
|
220
|
+
// Navigate to new path
|
|
221
|
+
await router.replace('/new-path');
|
|
222
|
+
await nextTick();
|
|
223
|
+
|
|
224
|
+
// Both parent and child components should see updates
|
|
225
|
+
expect(parentRoute?.path).toBe('/new-path');
|
|
226
|
+
expect(childRoute?.path).toBe('/new-path');
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe('RouterView Depth', () => {
|
|
231
|
+
it('should get depth in single RouterView', async () => {
|
|
232
|
+
let observedDepth: number | undefined;
|
|
233
|
+
|
|
234
|
+
const LeafProbe = defineComponent({
|
|
235
|
+
setup() {
|
|
236
|
+
const p = getCurrentInstance()!.proxy as any;
|
|
237
|
+
observedDepth = getRouterViewDepth(p);
|
|
238
|
+
return () => h('div');
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const Level1 = defineComponent({
|
|
243
|
+
setup() {
|
|
244
|
+
return () => h('div', [h(LeafProbe)]);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
router = new Router({
|
|
249
|
+
mode: RouterMode.memory,
|
|
250
|
+
routes: [{ path: '/level1', component: Level1 }],
|
|
251
|
+
base: new URL('http://localhost:8000/')
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
await router.replace('/level1');
|
|
255
|
+
|
|
256
|
+
const TestApp = defineComponent({
|
|
257
|
+
setup() {
|
|
258
|
+
useProvideRouter(router);
|
|
259
|
+
return () => h('div', [h(RouterView)]);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
app = createApp(TestApp);
|
|
264
|
+
app.mount('#app');
|
|
265
|
+
await nextTick();
|
|
266
|
+
|
|
267
|
+
expect(observedDepth).toBe(1);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should get depth in nested RouterView', async () => {
|
|
271
|
+
let observedDepth: number | undefined;
|
|
272
|
+
|
|
273
|
+
const LeafProbe = defineComponent({
|
|
274
|
+
setup() {
|
|
275
|
+
const p = getCurrentInstance()!.proxy as any;
|
|
276
|
+
observedDepth = getRouterViewDepth(p);
|
|
277
|
+
return () => h('div');
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
const Level1 = defineComponent({
|
|
282
|
+
setup() {
|
|
283
|
+
return () => h('div', [h(RouterView)]);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
const Leaf = defineComponent({
|
|
288
|
+
setup() {
|
|
289
|
+
return () => h('div', [h(LeafProbe)]);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
router = new Router({
|
|
294
|
+
mode: RouterMode.memory,
|
|
295
|
+
routes: [
|
|
296
|
+
{
|
|
297
|
+
path: '/level1',
|
|
298
|
+
component: Level1,
|
|
299
|
+
children: [{ path: 'leaf', component: Leaf }]
|
|
300
|
+
}
|
|
301
|
+
],
|
|
302
|
+
base: new URL('http://localhost:8000/')
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
await router.replace('/level1/leaf');
|
|
306
|
+
|
|
307
|
+
const TestApp = defineComponent({
|
|
308
|
+
setup() {
|
|
309
|
+
useProvideRouter(router);
|
|
310
|
+
return () => h('div', [h(RouterView)]);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
app = createApp(TestApp);
|
|
315
|
+
app.mount('#app');
|
|
316
|
+
await nextTick();
|
|
317
|
+
|
|
318
|
+
expect(observedDepth).toBe(2);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('should get depth in double-nested RouterViews', async () => {
|
|
322
|
+
let observedDepth: number | undefined;
|
|
323
|
+
|
|
324
|
+
const LeafProbe = defineComponent({
|
|
325
|
+
setup() {
|
|
326
|
+
const p = getCurrentInstance()!.proxy as any;
|
|
327
|
+
observedDepth = getRouterViewDepth(p);
|
|
328
|
+
return () => h('div');
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
const Level1 = defineComponent({
|
|
333
|
+
setup() {
|
|
334
|
+
return () => h('div', [h(RouterView)]);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
const Level2 = defineComponent({
|
|
339
|
+
setup() {
|
|
340
|
+
return () => h('div', [h(RouterView)]);
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
const Leaf = defineComponent({
|
|
345
|
+
setup() {
|
|
346
|
+
return () => h('div', [h(LeafProbe)]);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
router = new Router({
|
|
351
|
+
mode: RouterMode.memory,
|
|
352
|
+
routes: [
|
|
353
|
+
{
|
|
354
|
+
path: '/level1',
|
|
355
|
+
component: Level1,
|
|
356
|
+
children: [
|
|
357
|
+
{
|
|
358
|
+
path: 'level2',
|
|
359
|
+
component: Level2,
|
|
360
|
+
children: [{ path: 'leaf', component: Leaf }]
|
|
361
|
+
}
|
|
362
|
+
]
|
|
363
|
+
}
|
|
364
|
+
],
|
|
365
|
+
base: new URL('http://localhost:8000/')
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
await router.replace('/level1/level2/leaf');
|
|
369
|
+
|
|
370
|
+
const TestApp = defineComponent({
|
|
371
|
+
setup() {
|
|
372
|
+
useProvideRouter(router);
|
|
373
|
+
return () => h('div', [h(RouterView)]);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
app = createApp(TestApp);
|
|
378
|
+
app.mount('#app');
|
|
379
|
+
await nextTick();
|
|
380
|
+
|
|
381
|
+
expect(observedDepth).toBe(3);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it('should throw when no RouterView ancestor exists', async () => {
|
|
385
|
+
let callDepth: (() => void) | undefined;
|
|
386
|
+
|
|
387
|
+
const Probe = defineComponent({
|
|
388
|
+
setup() {
|
|
389
|
+
const p = getCurrentInstance()!.proxy as any;
|
|
390
|
+
callDepth = () => getRouterViewDepth(p);
|
|
391
|
+
return () => h('div');
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
const TestApp = defineComponent({
|
|
396
|
+
setup() {
|
|
397
|
+
useProvideRouter(router);
|
|
398
|
+
return () => h(Probe);
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
app = createApp(TestApp);
|
|
403
|
+
app.mount('#app');
|
|
404
|
+
await nextTick();
|
|
405
|
+
|
|
406
|
+
expect(() => callDepth!()).toThrow(
|
|
407
|
+
new Error(
|
|
408
|
+
'[@esmx/router-vue] RouterView depth not found. Please ensure a RouterView exists in ancestor components.'
|
|
409
|
+
)
|
|
410
|
+
);
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it('should return 0 for useRouterViewDepth without RouterView', async () => {
|
|
414
|
+
let observed = -1;
|
|
415
|
+
|
|
416
|
+
const Probe = defineComponent({
|
|
417
|
+
setup() {
|
|
418
|
+
observed = useRouterViewDepth();
|
|
419
|
+
return () => h('div');
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
const TestApp = defineComponent({
|
|
424
|
+
setup() {
|
|
425
|
+
useProvideRouter(router);
|
|
426
|
+
return () => h(Probe);
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
app = createApp(TestApp);
|
|
431
|
+
app.mount('#app');
|
|
432
|
+
await nextTick();
|
|
433
|
+
|
|
434
|
+
expect(observed).toBe(0);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it('should reflect depth via useRouterViewDepth at each level', async () => {
|
|
438
|
+
let level1Depth = -1;
|
|
439
|
+
let level2Depth = -1;
|
|
440
|
+
|
|
441
|
+
const Level2 = defineComponent({
|
|
442
|
+
setup() {
|
|
443
|
+
level2Depth = useRouterViewDepth();
|
|
444
|
+
return () => h('div');
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
const Level1 = defineComponent({
|
|
449
|
+
setup() {
|
|
450
|
+
level1Depth = useRouterViewDepth();
|
|
451
|
+
return () => h('div', [h(RouterView)]);
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
router = new Router({
|
|
456
|
+
mode: RouterMode.memory,
|
|
457
|
+
routes: [
|
|
458
|
+
{
|
|
459
|
+
path: '/level1',
|
|
460
|
+
component: Level1,
|
|
461
|
+
children: [{ path: 'level2', component: Level2 }]
|
|
462
|
+
}
|
|
463
|
+
],
|
|
464
|
+
base: new URL('http://localhost:8000/')
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
await router.replace('/level1/level2');
|
|
468
|
+
|
|
469
|
+
const TestApp = defineComponent({
|
|
470
|
+
setup() {
|
|
471
|
+
useProvideRouter(router);
|
|
472
|
+
return () => h('div', [h(RouterView)]);
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
app = createApp(TestApp);
|
|
477
|
+
app.mount('#app');
|
|
478
|
+
await nextTick();
|
|
479
|
+
|
|
480
|
+
expect(level1Depth).toBe(1);
|
|
481
|
+
expect(level2Depth).toBe(2);
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
});
|