@esmx/router 3.0.0-rc.29 → 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.
- package/README.zh-CN.md +82 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.mjs +0 -1
- package/package.json +3 -3
- package/src/index.ts +0 -3
- package/dist/index.test.d.ts +0 -1
- package/dist/index.test.mjs +0 -8
- package/dist/location.test.d.ts +0 -8
- package/dist/location.test.mjs +0 -370
- package/dist/matcher.test.d.ts +0 -1
- package/dist/matcher.test.mjs +0 -1492
- package/dist/micro-app.dom.test.d.ts +0 -1
- package/dist/micro-app.dom.test.mjs +0 -532
- package/dist/navigation.test.d.ts +0 -1
- package/dist/navigation.test.mjs +0 -681
- package/dist/route-task.test.d.ts +0 -1
- package/dist/route-task.test.mjs +0 -673
- package/dist/route-transition.test.d.ts +0 -1
- package/dist/route-transition.test.mjs +0 -146
- package/dist/route.test.d.ts +0 -1
- package/dist/route.test.mjs +0 -1664
- package/dist/router-back.test.d.ts +0 -1
- package/dist/router-back.test.mjs +0 -361
- package/dist/router-forward.test.d.ts +0 -1
- package/dist/router-forward.test.mjs +0 -376
- package/dist/router-go.test.d.ts +0 -1
- package/dist/router-go.test.mjs +0 -73
- package/dist/router-guards-cleanup.test.d.ts +0 -1
- package/dist/router-guards-cleanup.test.mjs +0 -437
- package/dist/router-push.test.d.ts +0 -1
- package/dist/router-push.test.mjs +0 -115
- package/dist/router-replace.test.d.ts +0 -1
- package/dist/router-replace.test.mjs +0 -114
- package/dist/router-resolve.test.d.ts +0 -1
- package/dist/router-resolve.test.mjs +0 -393
- package/dist/router-restart-app.dom.test.d.ts +0 -1
- package/dist/router-restart-app.dom.test.mjs +0 -616
- package/dist/router-window-navigation.test.d.ts +0 -1
- package/dist/router-window-navigation.test.mjs +0 -359
- package/dist/util.test.d.ts +0 -1
- package/dist/util.test.mjs +0 -1020
- package/src/index.test.ts +0 -9
- package/src/location.test.ts +0 -406
- package/src/matcher.test.ts +0 -1685
- package/src/micro-app.dom.test.ts +0 -708
- package/src/navigation.test.ts +0 -858
- package/src/route-task.test.ts +0 -901
- package/src/route-transition.test.ts +0 -178
- package/src/route.test.ts +0 -2014
- package/src/router-back.test.ts +0 -487
- package/src/router-forward.test.ts +0 -506
- package/src/router-go.test.ts +0 -91
- package/src/router-guards-cleanup.test.ts +0 -595
- package/src/router-push.test.ts +0 -140
- package/src/router-replace.test.ts +0 -139
- package/src/router-resolve.test.ts +0 -475
- package/src/router-restart-app.dom.test.ts +0 -783
- package/src/router-window-navigation.test.ts +0 -457
- package/src/util.test.ts +0 -1262
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { Router } from "./router.mjs";
|
|
3
|
-
import { RouteType } from "./types.mjs";
|
|
4
|
-
describe("Router Window Navigation Tests", () => {
|
|
5
|
-
let router;
|
|
6
|
-
let mockApps;
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
vi.clearAllMocks();
|
|
9
|
-
mockApps = {
|
|
10
|
-
home: vi.fn(() => ({
|
|
11
|
-
mount: vi.fn(),
|
|
12
|
-
unmount: vi.fn(),
|
|
13
|
-
renderToString: vi.fn().mockResolvedValue("<div>Home</div>")
|
|
14
|
-
})),
|
|
15
|
-
about: vi.fn(() => ({
|
|
16
|
-
mount: vi.fn(),
|
|
17
|
-
unmount: vi.fn(),
|
|
18
|
-
renderToString: vi.fn().mockResolvedValue("<div>About</div>")
|
|
19
|
-
})),
|
|
20
|
-
user: vi.fn(() => ({
|
|
21
|
-
mount: vi.fn(),
|
|
22
|
-
unmount: vi.fn(),
|
|
23
|
-
renderToString: vi.fn().mockResolvedValue("<div>User</div>")
|
|
24
|
-
}))
|
|
25
|
-
};
|
|
26
|
-
router = new Router({
|
|
27
|
-
routes: [
|
|
28
|
-
{ path: "/", app: "home" },
|
|
29
|
-
{ path: "/about", app: "about" },
|
|
30
|
-
{ path: "/user/:id", app: "user" }
|
|
31
|
-
],
|
|
32
|
-
apps: mockApps
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
function createWindowNavigationTests(methodName, expectedIsPush) {
|
|
36
|
-
describe("\u{1FA9F} ".concat(methodName, " Core Functionality Tests"), () => {
|
|
37
|
-
it("should support using current route path", async () => {
|
|
38
|
-
await router.push("/about");
|
|
39
|
-
const result = await router[methodName]("/about");
|
|
40
|
-
expect(result.type).toBe(RouteType[methodName]);
|
|
41
|
-
expect(result.path).toBe("/about");
|
|
42
|
-
expect(result.isPush).toBe(expectedIsPush);
|
|
43
|
-
expect(result.handle).not.toBeNull();
|
|
44
|
-
});
|
|
45
|
-
it("should support string path parameters", async () => {
|
|
46
|
-
const result = await router[methodName]("/user/123");
|
|
47
|
-
expect(result.type).toBe(RouteType[methodName]);
|
|
48
|
-
expect(result.path).toBe("/user/123");
|
|
49
|
-
expect(result.params.id).toBe("123");
|
|
50
|
-
expect(result.isPush).toBe(expectedIsPush);
|
|
51
|
-
expect(result.handle).not.toBeNull();
|
|
52
|
-
});
|
|
53
|
-
it("should support object parameters", async () => {
|
|
54
|
-
const result = await router[methodName]({
|
|
55
|
-
path: "/user/456",
|
|
56
|
-
query: { tab: "profile" },
|
|
57
|
-
hash: "section1"
|
|
58
|
-
});
|
|
59
|
-
expect(result.type).toBe(RouteType[methodName]);
|
|
60
|
-
expect(result.path).toBe("/user/456");
|
|
61
|
-
expect(result.params.id).toBe("456");
|
|
62
|
-
expect(result.query.tab).toBe("profile");
|
|
63
|
-
expect(result.url.hash).toBe("#section1");
|
|
64
|
-
expect(result.isPush).toBe(expectedIsPush);
|
|
65
|
-
expect(result.handle).not.toBeNull();
|
|
66
|
-
});
|
|
67
|
-
it("should correctly handle complete URLs", async () => {
|
|
68
|
-
const result = await router[methodName](
|
|
69
|
-
"https://example.com/user/789?sort=name#top"
|
|
70
|
-
);
|
|
71
|
-
expect(result.type).toBe(RouteType[methodName]);
|
|
72
|
-
expect(result.url.href).toBe(
|
|
73
|
-
"https://example.com/user/789?sort=name#top"
|
|
74
|
-
);
|
|
75
|
-
expect(result.isPush).toBe(expectedIsPush);
|
|
76
|
-
expect(result.handle).not.toBeNull();
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
describe("\u{1F3AF} ".concat(methodName, " Specific Behavior Tests"), () => {
|
|
80
|
-
it("should set correct isPush flag", async () => {
|
|
81
|
-
const result = await router[methodName]("/about");
|
|
82
|
-
expect(result.isPush).toBe(expectedIsPush);
|
|
83
|
-
expect(result.type).toBe(RouteType[methodName]);
|
|
84
|
-
});
|
|
85
|
-
it("should call location handler", async () => {
|
|
86
|
-
let locationCalled = false;
|
|
87
|
-
let receivedRoute = null;
|
|
88
|
-
const windowRouter = new Router({
|
|
89
|
-
routes: [{ path: "/", app: "home" }],
|
|
90
|
-
apps: mockApps,
|
|
91
|
-
fallback: (to, from) => {
|
|
92
|
-
locationCalled = true;
|
|
93
|
-
receivedRoute = to;
|
|
94
|
-
return { windowNavigation: true };
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
await windowRouter.push("/");
|
|
98
|
-
const result = await windowRouter[methodName]("/about");
|
|
99
|
-
expect(locationCalled).toBe(true);
|
|
100
|
-
expect(receivedRoute.isPush).toBe(expectedIsPush);
|
|
101
|
-
expect(result.handleResult).toEqual({ windowNavigation: true });
|
|
102
|
-
windowRouter.destroy();
|
|
103
|
-
});
|
|
104
|
-
it("should not update current route state", async () => {
|
|
105
|
-
await router.push("/about");
|
|
106
|
-
const beforeRoute = router.route;
|
|
107
|
-
await router[methodName]("/user/123");
|
|
108
|
-
const afterRoute = router.route;
|
|
109
|
-
expect(afterRoute.path).toBe(beforeRoute.path);
|
|
110
|
-
expect(afterRoute.url.href).toBe(beforeRoute.url.href);
|
|
111
|
-
});
|
|
112
|
-
it("should not trigger MicroApp update", async () => {
|
|
113
|
-
const updateSpy = vi.spyOn(router.microApp, "_update");
|
|
114
|
-
await router[methodName]("/user/123");
|
|
115
|
-
expect(updateSpy).not.toHaveBeenCalled();
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
describe("\u{1F6E1}\uFE0F ".concat(methodName, " Route Guards Tests"), () => {
|
|
119
|
-
it("should execute beforeEach guards", async () => {
|
|
120
|
-
let guardCalled = false;
|
|
121
|
-
const unregister = router.beforeEach(async (to, from) => {
|
|
122
|
-
guardCalled = true;
|
|
123
|
-
expect(to.isPush).toBe(expectedIsPush);
|
|
124
|
-
});
|
|
125
|
-
await router[methodName]("/about");
|
|
126
|
-
expect(guardCalled).toBe(true);
|
|
127
|
-
unregister();
|
|
128
|
-
});
|
|
129
|
-
it("should abort navigation when guard returns false", async () => {
|
|
130
|
-
const unregister = router.beforeEach((to, from) => {
|
|
131
|
-
return false;
|
|
132
|
-
});
|
|
133
|
-
await expect(router[methodName]("/about")).rejects.toThrow(
|
|
134
|
-
"Navigation was aborted"
|
|
135
|
-
);
|
|
136
|
-
unregister();
|
|
137
|
-
});
|
|
138
|
-
it("should support guard redirects", async () => {
|
|
139
|
-
const unregister = router.beforeEach(async (to) => {
|
|
140
|
-
if (to.path === "/about") {
|
|
141
|
-
return "/user/redirect";
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
const result = await router[methodName]("/about");
|
|
145
|
-
expect(result.path).toBe("/user/redirect");
|
|
146
|
-
expect(result.params.id).toBe("redirect");
|
|
147
|
-
unregister();
|
|
148
|
-
});
|
|
149
|
-
it("should execute afterEach guards", async () => {
|
|
150
|
-
let guardCalled = false;
|
|
151
|
-
const unregister = router.afterEach((to, from) => {
|
|
152
|
-
guardCalled = true;
|
|
153
|
-
expect(to.isPush).toBe(expectedIsPush);
|
|
154
|
-
});
|
|
155
|
-
await router[methodName]("/about");
|
|
156
|
-
expect(guardCalled).toBe(true);
|
|
157
|
-
unregister();
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
describe("\u{1F3AD} ".concat(methodName, " Edge Cases Tests"), () => {
|
|
161
|
-
it("should handle non-existent routes", async () => {
|
|
162
|
-
const result = await router[methodName]("/nonexistent");
|
|
163
|
-
expect(result.handle).not.toBeNull();
|
|
164
|
-
expect(result.matched.length).toBe(0);
|
|
165
|
-
expect(result.isPush).toBe(expectedIsPush);
|
|
166
|
-
});
|
|
167
|
-
it("should handle empty string path", async () => {
|
|
168
|
-
const result = await router[methodName]("");
|
|
169
|
-
expect(result.handle).not.toBeNull();
|
|
170
|
-
expect(result.isPush).toBe(expectedIsPush);
|
|
171
|
-
});
|
|
172
|
-
it("should handle special characters", async () => {
|
|
173
|
-
const result = await router[methodName](
|
|
174
|
-
"/user/\u6D4B\u8BD5\u7528\u6237?name=\u5F20\u4E09&age=25#\u4E2A\u4EBA\u4FE1\u606F"
|
|
175
|
-
);
|
|
176
|
-
expect(result.handle).not.toBeNull();
|
|
177
|
-
expect(result.isPush).toBe(expectedIsPush);
|
|
178
|
-
expect(result.url.pathname).toContain(
|
|
179
|
-
"%E6%B5%8B%E8%AF%95%E7%94%A8%E6%88%B7"
|
|
180
|
-
);
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
describe("\u26A1 ".concat(methodName, " Task Cancellation and Concurrency Control"), () => {
|
|
184
|
-
it("should support concurrent calls", async () => {
|
|
185
|
-
const promises = [
|
|
186
|
-
router[methodName]("/user/1").catch((err) => err),
|
|
187
|
-
router[methodName]("/user/2").catch((err) => err),
|
|
188
|
-
router[methodName]("/user/3").catch((err) => err)
|
|
189
|
-
];
|
|
190
|
-
const results = await Promise.all(promises);
|
|
191
|
-
const successResults = results.filter(
|
|
192
|
-
(r) => !(r instanceof Error) && r.handle !== null
|
|
193
|
-
);
|
|
194
|
-
const errorResults = results.filter((r) => r instanceof Error);
|
|
195
|
-
expect(successResults.length).toBeGreaterThan(0);
|
|
196
|
-
expect(successResults.length + errorResults.length).toBe(3);
|
|
197
|
-
successResults.forEach((result) => {
|
|
198
|
-
expect(result.isPush).toBe(expectedIsPush);
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
it("should correctly handle rapid consecutive calls", async () => {
|
|
202
|
-
const results = [];
|
|
203
|
-
for (let i = 0; i < 5; i++) {
|
|
204
|
-
results.push(await router[methodName]("/user/".concat(i)));
|
|
205
|
-
}
|
|
206
|
-
results.forEach((result, index) => {
|
|
207
|
-
expect(result.handle).not.toBeNull();
|
|
208
|
-
expect(result.params.id).toBe(String(index));
|
|
209
|
-
expect(result.isPush).toBe(expectedIsPush);
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
describe("\u274C ".concat(methodName, " Error Handling"), () => {
|
|
214
|
-
it("should handle exceptions in guards", async () => {
|
|
215
|
-
const unregister = router.beforeEach(async () => {
|
|
216
|
-
throw new Error("Guard error");
|
|
217
|
-
});
|
|
218
|
-
await expect(router[methodName]("/about")).rejects.toThrow();
|
|
219
|
-
unregister();
|
|
220
|
-
});
|
|
221
|
-
it("should handle location handler exceptions", async () => {
|
|
222
|
-
const windowRouter = new Router({
|
|
223
|
-
routes: [{ path: "/", app: "home" }],
|
|
224
|
-
apps: mockApps,
|
|
225
|
-
fallback: () => {
|
|
226
|
-
throw new Error("Location handler error");
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
await windowRouter.push("/");
|
|
230
|
-
await expect(
|
|
231
|
-
windowRouter[methodName]("/about")
|
|
232
|
-
).rejects.toThrow();
|
|
233
|
-
windowRouter.destroy();
|
|
234
|
-
});
|
|
235
|
-
});
|
|
236
|
-
describe("\u{1F9E9} ".concat(methodName, " Async Component Handling"), () => {
|
|
237
|
-
it("should correctly handle async components", async () => {
|
|
238
|
-
const asyncRouter = new Router({
|
|
239
|
-
routes: [
|
|
240
|
-
{
|
|
241
|
-
path: "/async",
|
|
242
|
-
app: "home",
|
|
243
|
-
asyncComponent: async () => {
|
|
244
|
-
await new Promise(
|
|
245
|
-
(resolve) => setTimeout(resolve, 10)
|
|
246
|
-
);
|
|
247
|
-
return () => "AsyncComponent";
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
],
|
|
251
|
-
apps: mockApps,
|
|
252
|
-
fallback: (to, from) => {
|
|
253
|
-
return { windowNavigation: true };
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
const result = await asyncRouter[methodName]("/async");
|
|
257
|
-
expect(result.handle).not.toBeNull();
|
|
258
|
-
expect(result.isPush).toBe(expectedIsPush);
|
|
259
|
-
expect(result.matched[0].component).toBeUndefined();
|
|
260
|
-
expect(result.matched[0].asyncComponent).toBeDefined();
|
|
261
|
-
expect(result.handleResult).toEqual({ windowNavigation: true });
|
|
262
|
-
asyncRouter.destroy();
|
|
263
|
-
});
|
|
264
|
-
it("should handle async component loading failures", async () => {
|
|
265
|
-
const asyncRouter = new Router({
|
|
266
|
-
routes: [
|
|
267
|
-
{
|
|
268
|
-
path: "/async-error",
|
|
269
|
-
app: "home",
|
|
270
|
-
asyncComponent: async () => {
|
|
271
|
-
throw new Error("Component load failed");
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
],
|
|
275
|
-
apps: mockApps,
|
|
276
|
-
fallback: (to, from) => {
|
|
277
|
-
return { fallbackHandled: true };
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
const result = await asyncRouter[methodName]("/async-error");
|
|
281
|
-
expect(result.handle).not.toBeNull();
|
|
282
|
-
expect(result.matched[0].component).toBeUndefined();
|
|
283
|
-
expect(result.matched[0].asyncComponent).toBeDefined();
|
|
284
|
-
expect(result.handleResult).toEqual({ fallbackHandled: true });
|
|
285
|
-
asyncRouter.destroy();
|
|
286
|
-
});
|
|
287
|
-
});
|
|
288
|
-
describe("\u{1F527} ".concat(methodName, " Differences from Other Methods"), () => {
|
|
289
|
-
it("should behave differently from push/replace methods", async () => {
|
|
290
|
-
await router.push("/about");
|
|
291
|
-
const pushResult = await router.push("/user/123");
|
|
292
|
-
const windowResult = await router[methodName]("/user/456");
|
|
293
|
-
expect(router.route.path).toBe("/user/123");
|
|
294
|
-
expect(windowResult.isPush).toBe(expectedIsPush);
|
|
295
|
-
expect(windowResult.type).toBe(RouteType[methodName]);
|
|
296
|
-
expect(pushResult.type).toBe(RouteType.push);
|
|
297
|
-
expect(windowResult.type).toBe(RouteType[methodName]);
|
|
298
|
-
});
|
|
299
|
-
it("should maintain consistency with resolve method in URL parsing", async () => {
|
|
300
|
-
const resolvedRoute = router.resolve("/user/789");
|
|
301
|
-
const windowRoute = await router[methodName]("/user/789");
|
|
302
|
-
expect(windowRoute.url.href).toBe(resolvedRoute.url.href);
|
|
303
|
-
expect(windowRoute.params).toEqual(resolvedRoute.params);
|
|
304
|
-
expect(windowRoute.matched).toEqual(resolvedRoute.matched);
|
|
305
|
-
expect(windowRoute.type).toBe(RouteType[methodName]);
|
|
306
|
-
expect(resolvedRoute.type).toBe(RouteType.push);
|
|
307
|
-
expect(windowRoute.isPush).toBe(expectedIsPush);
|
|
308
|
-
expect(resolvedRoute.isPush).toBe(true);
|
|
309
|
-
});
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
createWindowNavigationTests("pushWindow", true);
|
|
313
|
-
createWindowNavigationTests("replaceWindow", false);
|
|
314
|
-
describe("\u{1F504} pushWindow and replaceWindow Comparison Tests", () => {
|
|
315
|
-
it("the only difference between the two methods should be the isPush flag", async () => {
|
|
316
|
-
const pushResult = await router.pushWindow("/user/123");
|
|
317
|
-
const replaceResult = await router.replaceWindow("/user/123");
|
|
318
|
-
expect(pushResult.url.href).toBe(replaceResult.url.href);
|
|
319
|
-
expect(pushResult.params).toEqual(replaceResult.params);
|
|
320
|
-
expect(pushResult.query).toEqual(replaceResult.query);
|
|
321
|
-
expect(pushResult.url.hash).toBe(replaceResult.url.hash);
|
|
322
|
-
expect(pushResult.matched).toEqual(replaceResult.matched);
|
|
323
|
-
expect(pushResult.isPush).toBe(true);
|
|
324
|
-
expect(replaceResult.isPush).toBe(false);
|
|
325
|
-
expect(pushResult.type).toBe(RouteType.pushWindow);
|
|
326
|
-
expect(replaceResult.type).toBe(RouteType.replaceWindow);
|
|
327
|
-
});
|
|
328
|
-
it("both methods should call the same location handler", async () => {
|
|
329
|
-
const locationCalls = [];
|
|
330
|
-
const windowRouter = new Router({
|
|
331
|
-
routes: [{ path: "/", app: "home" }],
|
|
332
|
-
apps: mockApps,
|
|
333
|
-
fallback: (to, from) => {
|
|
334
|
-
locationCalls.push({
|
|
335
|
-
method: to.type,
|
|
336
|
-
isPush: to.isPush,
|
|
337
|
-
path: to.path
|
|
338
|
-
});
|
|
339
|
-
return { called: true };
|
|
340
|
-
}
|
|
341
|
-
});
|
|
342
|
-
await windowRouter.push("/");
|
|
343
|
-
await windowRouter.pushWindow("/test");
|
|
344
|
-
await windowRouter.replaceWindow("/test");
|
|
345
|
-
expect(locationCalls).toHaveLength(2);
|
|
346
|
-
expect(locationCalls[0]).toEqual({
|
|
347
|
-
method: "pushWindow",
|
|
348
|
-
isPush: true,
|
|
349
|
-
path: "/test"
|
|
350
|
-
});
|
|
351
|
-
expect(locationCalls[1]).toEqual({
|
|
352
|
-
method: "replaceWindow",
|
|
353
|
-
isPush: false,
|
|
354
|
-
path: "/test"
|
|
355
|
-
});
|
|
356
|
-
windowRouter.destroy();
|
|
357
|
-
});
|
|
358
|
-
});
|
|
359
|
-
});
|
package/dist/util.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|