@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.
- package/README.zh-CN.md +82 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.mjs +0 -1
- package/package.json +4 -4
- 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
package/src/route-task.test.ts
DELETED
|
@@ -1,901 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
RouteNavigationAbortedError,
|
|
4
|
-
RouteTaskCancelledError,
|
|
5
|
-
RouteTaskExecutionError
|
|
6
|
-
} from './error';
|
|
7
|
-
import { parsedOptions } from './options';
|
|
8
|
-
import { Route } from './route';
|
|
9
|
-
import { RouteTaskController, createRouteTask } from './route-task';
|
|
10
|
-
import type { RouteTask, RouteTaskOptions } from './route-task';
|
|
11
|
-
import type { Router } from './router';
|
|
12
|
-
import { RouteType } from './types';
|
|
13
|
-
import type { RouteConfirmHookResult, RouterParsedOptions } from './types';
|
|
14
|
-
|
|
15
|
-
// Helper function to create real RouterParsedOptions
|
|
16
|
-
function createRealOptions(): RouterParsedOptions {
|
|
17
|
-
return parsedOptions({
|
|
18
|
-
base: new URL('http://localhost/'),
|
|
19
|
-
routes: [
|
|
20
|
-
{ path: '/test', component: 'TestComponent' },
|
|
21
|
-
{ path: '/about', component: 'AboutComponent' },
|
|
22
|
-
{ path: '/redirected', component: 'RedirectedComponent' },
|
|
23
|
-
{ path: '/admin', component: 'AdminComponent' },
|
|
24
|
-
{ path: '/login', component: 'LoginComponent' },
|
|
25
|
-
{ path: '/home', component: 'HomeComponent' }
|
|
26
|
-
]
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Helper function to create mock router
|
|
31
|
-
function createMockRouter(): Router {
|
|
32
|
-
const options = createRealOptions();
|
|
33
|
-
return {
|
|
34
|
-
parsedOptions: options
|
|
35
|
-
} as Router;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
describe('createRouteTask', () => {
|
|
39
|
-
it('should return original route when task array is empty', async () => {
|
|
40
|
-
const router = createMockRouter();
|
|
41
|
-
const to = new Route({
|
|
42
|
-
options: router.parsedOptions,
|
|
43
|
-
toType: RouteType.push,
|
|
44
|
-
toInput: '/test'
|
|
45
|
-
});
|
|
46
|
-
const from = new Route({
|
|
47
|
-
options: router.parsedOptions,
|
|
48
|
-
toType: RouteType.push,
|
|
49
|
-
toInput: '/home'
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const tasks: RouteTask[] = [];
|
|
53
|
-
|
|
54
|
-
const result = await createRouteTask({
|
|
55
|
-
to,
|
|
56
|
-
from,
|
|
57
|
-
tasks,
|
|
58
|
-
router
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
expect(result).toBe(to);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('should execute tasks in sequence', async () => {
|
|
65
|
-
const router = createMockRouter();
|
|
66
|
-
const to = new Route({
|
|
67
|
-
options: router.parsedOptions,
|
|
68
|
-
toType: RouteType.push,
|
|
69
|
-
toInput: '/test'
|
|
70
|
-
});
|
|
71
|
-
const from = new Route({
|
|
72
|
-
options: router.parsedOptions,
|
|
73
|
-
toType: RouteType.push,
|
|
74
|
-
toInput: '/home'
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
const executionOrder: string[] = [];
|
|
78
|
-
|
|
79
|
-
const firstTask = async (
|
|
80
|
-
route: Route,
|
|
81
|
-
fromRoute: Route | null,
|
|
82
|
-
router: Router
|
|
83
|
-
) => {
|
|
84
|
-
executionOrder.push('task1');
|
|
85
|
-
return; // Continue execution.
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const secondTask = async (
|
|
89
|
-
route: Route,
|
|
90
|
-
fromRoute: Route | null,
|
|
91
|
-
router: Router
|
|
92
|
-
) => {
|
|
93
|
-
executionOrder.push('task2');
|
|
94
|
-
// Return handler function
|
|
95
|
-
return async () => ({ success: true });
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const tasks: RouteTask[] = [
|
|
99
|
-
{
|
|
100
|
-
name: 'beforeEach',
|
|
101
|
-
task: firstTask
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
name: 'override',
|
|
105
|
-
task: secondTask
|
|
106
|
-
}
|
|
107
|
-
];
|
|
108
|
-
|
|
109
|
-
const result = await createRouteTask({
|
|
110
|
-
to,
|
|
111
|
-
from,
|
|
112
|
-
tasks,
|
|
113
|
-
router
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
expect(executionOrder).toEqual(['task1', 'task2']);
|
|
117
|
-
expect(result).toBe(to);
|
|
118
|
-
expect(to.handle).toBeTypeOf('function');
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('should set handle when task returns a function', async () => {
|
|
122
|
-
const router = createMockRouter();
|
|
123
|
-
const to = new Route({
|
|
124
|
-
options: router.parsedOptions,
|
|
125
|
-
toType: RouteType.push,
|
|
126
|
-
toInput: '/test'
|
|
127
|
-
});
|
|
128
|
-
const from = new Route({
|
|
129
|
-
options: router.parsedOptions,
|
|
130
|
-
toType: RouteType.push,
|
|
131
|
-
toInput: '/home'
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
// Real handler function.
|
|
135
|
-
const handleFunction = async (
|
|
136
|
-
to: Route,
|
|
137
|
-
from: Route | null,
|
|
138
|
-
router: Router
|
|
139
|
-
) => {
|
|
140
|
-
return { message: 'Route handled successfully' };
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const successTask = async (
|
|
144
|
-
route: Route,
|
|
145
|
-
fromRoute: Route | null,
|
|
146
|
-
router: Router
|
|
147
|
-
) => {
|
|
148
|
-
return handleFunction; // Return handler function.
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
const tasks: RouteTask[] = [
|
|
152
|
-
{
|
|
153
|
-
name: 'beforeEach',
|
|
154
|
-
task: successTask
|
|
155
|
-
}
|
|
156
|
-
];
|
|
157
|
-
|
|
158
|
-
const result = await createRouteTask({
|
|
159
|
-
to,
|
|
160
|
-
from,
|
|
161
|
-
tasks,
|
|
162
|
-
router
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
expect(result).toBe(to);
|
|
166
|
-
expect(to.handle).toBeTypeOf('function');
|
|
167
|
-
expect(to.handle).not.toBeNull();
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('should throw RouteNavigationAbortedError when task returns false', async () => {
|
|
171
|
-
const router = createMockRouter();
|
|
172
|
-
const to = new Route({
|
|
173
|
-
options: router.parsedOptions,
|
|
174
|
-
toType: RouteType.push,
|
|
175
|
-
toInput: '/test'
|
|
176
|
-
});
|
|
177
|
-
const from = new Route({
|
|
178
|
-
options: router.parsedOptions,
|
|
179
|
-
toType: RouteType.push,
|
|
180
|
-
toInput: '/home'
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
// Real blocking task.
|
|
184
|
-
const blockingTask = async (
|
|
185
|
-
route: Route,
|
|
186
|
-
fromRoute: Route | null,
|
|
187
|
-
router: Router
|
|
188
|
-
): Promise<RouteConfirmHookResult> => {
|
|
189
|
-
const shouldProceed = false;
|
|
190
|
-
return shouldProceed ? void 0 : false; // Return false to prevent navigation.
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
const tasks: RouteTask[] = [
|
|
194
|
-
{
|
|
195
|
-
name: 'beforeEach',
|
|
196
|
-
task: blockingTask
|
|
197
|
-
}
|
|
198
|
-
];
|
|
199
|
-
|
|
200
|
-
await expect(
|
|
201
|
-
createRouteTask({
|
|
202
|
-
to,
|
|
203
|
-
from,
|
|
204
|
-
tasks,
|
|
205
|
-
router
|
|
206
|
-
})
|
|
207
|
-
).rejects.toThrow(RouteNavigationAbortedError);
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it('should handle redirection when task returns a route location string', async () => {
|
|
211
|
-
const router = createMockRouter();
|
|
212
|
-
const to = new Route({
|
|
213
|
-
options: router.parsedOptions,
|
|
214
|
-
toType: RouteType.push,
|
|
215
|
-
toInput: '/test'
|
|
216
|
-
});
|
|
217
|
-
const from = new Route({
|
|
218
|
-
options: router.parsedOptions,
|
|
219
|
-
toType: RouteType.push,
|
|
220
|
-
toInput: '/home'
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
// Real redirection task function.
|
|
224
|
-
const redirectTask = async (
|
|
225
|
-
route: Route,
|
|
226
|
-
fromRoute: Route | null,
|
|
227
|
-
router: Router
|
|
228
|
-
) => {
|
|
229
|
-
if (route.path === '/test') {
|
|
230
|
-
return '/redirected';
|
|
231
|
-
}
|
|
232
|
-
// Other paths pass through directly (returning void means continue).
|
|
233
|
-
return;
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
const tasks: RouteTask[] = [
|
|
237
|
-
{
|
|
238
|
-
name: 'beforeEach',
|
|
239
|
-
task: redirectTask
|
|
240
|
-
}
|
|
241
|
-
];
|
|
242
|
-
|
|
243
|
-
const result = await createRouteTask({
|
|
244
|
-
to,
|
|
245
|
-
from,
|
|
246
|
-
tasks,
|
|
247
|
-
router
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
// Should return a new Route object for the redirected path
|
|
251
|
-
expect(result).toBeInstanceOf(Route);
|
|
252
|
-
expect(result.path).toBe('/redirected');
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it('should throw RouteTaskExecutionError when task throws an error', async () => {
|
|
256
|
-
const router = createMockRouter();
|
|
257
|
-
const to = new Route({
|
|
258
|
-
options: router.parsedOptions,
|
|
259
|
-
toType: RouteType.push,
|
|
260
|
-
toInput: '/test'
|
|
261
|
-
});
|
|
262
|
-
const from = new Route({
|
|
263
|
-
options: router.parsedOptions,
|
|
264
|
-
toType: RouteType.push,
|
|
265
|
-
toInput: '/home'
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
// A real task that throws an error.
|
|
269
|
-
const errorTask = async (
|
|
270
|
-
route: Route,
|
|
271
|
-
fromRoute: Route | null,
|
|
272
|
-
router: Router
|
|
273
|
-
) => {
|
|
274
|
-
throw new Error('Task execution failed');
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
const tasks: RouteTask[] = [
|
|
278
|
-
{
|
|
279
|
-
name: 'beforeEach',
|
|
280
|
-
task: errorTask
|
|
281
|
-
}
|
|
282
|
-
];
|
|
283
|
-
|
|
284
|
-
await expect(
|
|
285
|
-
createRouteTask({
|
|
286
|
-
to,
|
|
287
|
-
from,
|
|
288
|
-
tasks,
|
|
289
|
-
router
|
|
290
|
-
})
|
|
291
|
-
).rejects.toThrow(RouteTaskExecutionError);
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
it('should handle non-Error exceptions and convert them to Error instances', async () => {
|
|
295
|
-
const router = createMockRouter();
|
|
296
|
-
const to = new Route({
|
|
297
|
-
options: router.parsedOptions,
|
|
298
|
-
toType: RouteType.push,
|
|
299
|
-
toInput: '/test'
|
|
300
|
-
});
|
|
301
|
-
const from = new Route({
|
|
302
|
-
options: router.parsedOptions,
|
|
303
|
-
toType: RouteType.push,
|
|
304
|
-
toInput: '/home'
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
// Task that throws a string instead of Error
|
|
308
|
-
const stringErrorTask = async (
|
|
309
|
-
route: Route,
|
|
310
|
-
fromRoute: Route | null,
|
|
311
|
-
router: Router
|
|
312
|
-
) => {
|
|
313
|
-
throw 'String error message'; // eslint-disable-line prefer-promise-reject-errors
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
// Task that throws a number
|
|
317
|
-
const numberErrorTask = async (
|
|
318
|
-
route: Route,
|
|
319
|
-
fromRoute: Route | null,
|
|
320
|
-
router: Router
|
|
321
|
-
) => {
|
|
322
|
-
throw 404; // eslint-disable-line prefer-promise-reject-errors
|
|
323
|
-
};
|
|
324
|
-
|
|
325
|
-
// Task that throws an object
|
|
326
|
-
const objectErrorTask = async (
|
|
327
|
-
route: Route,
|
|
328
|
-
fromRoute: Route | null,
|
|
329
|
-
router: Router
|
|
330
|
-
) => {
|
|
331
|
-
throw { code: 'CUSTOM_ERROR', message: 'Custom error object' }; // eslint-disable-line prefer-promise-reject-errors
|
|
332
|
-
};
|
|
333
|
-
|
|
334
|
-
// Test string error
|
|
335
|
-
const stringTasks: RouteTask[] = [
|
|
336
|
-
{ name: 'stringError', task: stringErrorTask }
|
|
337
|
-
];
|
|
338
|
-
try {
|
|
339
|
-
await createRouteTask({ to, from, tasks: stringTasks, router });
|
|
340
|
-
} catch (error) {
|
|
341
|
-
expect(error).toBeInstanceOf(RouteTaskExecutionError);
|
|
342
|
-
expect(
|
|
343
|
-
(error as RouteTaskExecutionError).originalError
|
|
344
|
-
).toBeInstanceOf(Error);
|
|
345
|
-
expect(
|
|
346
|
-
(error as RouteTaskExecutionError).originalError.message
|
|
347
|
-
).toBe('String error message');
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Test number error
|
|
351
|
-
const numberTasks: RouteTask[] = [
|
|
352
|
-
{ name: 'numberError', task: numberErrorTask }
|
|
353
|
-
];
|
|
354
|
-
try {
|
|
355
|
-
await createRouteTask({ to, from, tasks: numberTasks, router });
|
|
356
|
-
} catch (error) {
|
|
357
|
-
expect(error).toBeInstanceOf(RouteTaskExecutionError);
|
|
358
|
-
expect(
|
|
359
|
-
(error as RouteTaskExecutionError).originalError
|
|
360
|
-
).toBeInstanceOf(Error);
|
|
361
|
-
expect(
|
|
362
|
-
(error as RouteTaskExecutionError).originalError.message
|
|
363
|
-
).toBe('404');
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// Test object error
|
|
367
|
-
const objectTasks: RouteTask[] = [
|
|
368
|
-
{ name: 'objectError', task: objectErrorTask }
|
|
369
|
-
];
|
|
370
|
-
try {
|
|
371
|
-
await createRouteTask({ to, from, tasks: objectTasks, router });
|
|
372
|
-
} catch (error) {
|
|
373
|
-
expect(error).toBeInstanceOf(RouteTaskExecutionError);
|
|
374
|
-
expect(
|
|
375
|
-
(error as RouteTaskExecutionError).originalError
|
|
376
|
-
).toBeInstanceOf(Error);
|
|
377
|
-
expect(
|
|
378
|
-
(error as RouteTaskExecutionError).originalError.message
|
|
379
|
-
).toBe('[object Object]');
|
|
380
|
-
}
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
it('should not execute subsequent tasks once an error is thrown', async () => {
|
|
384
|
-
const router = createMockRouter();
|
|
385
|
-
const to = new Route({
|
|
386
|
-
options: router.parsedOptions,
|
|
387
|
-
toType: RouteType.push,
|
|
388
|
-
toInput: '/test'
|
|
389
|
-
});
|
|
390
|
-
const from = new Route({
|
|
391
|
-
options: router.parsedOptions,
|
|
392
|
-
toType: RouteType.push,
|
|
393
|
-
toInput: '/home'
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
const executionOrder: string[] = [];
|
|
397
|
-
|
|
398
|
-
const firstTask = async (
|
|
399
|
-
route: Route,
|
|
400
|
-
fromRoute: Route | null,
|
|
401
|
-
router: Router
|
|
402
|
-
) => {
|
|
403
|
-
executionOrder.push('task1');
|
|
404
|
-
throw new Error('Task failed');
|
|
405
|
-
};
|
|
406
|
-
|
|
407
|
-
const secondTask = async (
|
|
408
|
-
route: Route,
|
|
409
|
-
fromRoute: Route | null,
|
|
410
|
-
router: Router
|
|
411
|
-
) => {
|
|
412
|
-
executionOrder.push('task2'); // This should NOT be executed.
|
|
413
|
-
return;
|
|
414
|
-
};
|
|
415
|
-
|
|
416
|
-
const tasks: RouteTask[] = [
|
|
417
|
-
{
|
|
418
|
-
name: 'beforeEach',
|
|
419
|
-
task: firstTask
|
|
420
|
-
},
|
|
421
|
-
{
|
|
422
|
-
name: 'beforeEnter',
|
|
423
|
-
task: secondTask
|
|
424
|
-
}
|
|
425
|
-
];
|
|
426
|
-
|
|
427
|
-
await expect(
|
|
428
|
-
createRouteTask({
|
|
429
|
-
to,
|
|
430
|
-
from,
|
|
431
|
-
tasks,
|
|
432
|
-
router
|
|
433
|
-
})
|
|
434
|
-
).rejects.toThrow(RouteTaskExecutionError);
|
|
435
|
-
|
|
436
|
-
expect(executionOrder).toEqual(['task1']); // Only the first task should be executed.
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
it('should handle null from route parameter', async () => {
|
|
440
|
-
const router = createMockRouter();
|
|
441
|
-
const to = new Route({
|
|
442
|
-
options: router.parsedOptions,
|
|
443
|
-
toType: RouteType.push,
|
|
444
|
-
toInput: '/test'
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
const checkFromRouteTask = async (
|
|
448
|
-
route: Route,
|
|
449
|
-
fromRoute: Route | null,
|
|
450
|
-
router: Router
|
|
451
|
-
) => {
|
|
452
|
-
expect(fromRoute).toBeNull();
|
|
453
|
-
return async () => ({ success: true }); // Return handler
|
|
454
|
-
};
|
|
455
|
-
|
|
456
|
-
const tasks: RouteTask[] = [
|
|
457
|
-
{
|
|
458
|
-
name: 'beforeEach',
|
|
459
|
-
task: checkFromRouteTask
|
|
460
|
-
}
|
|
461
|
-
];
|
|
462
|
-
|
|
463
|
-
const result = await createRouteTask({
|
|
464
|
-
to,
|
|
465
|
-
from: null,
|
|
466
|
-
tasks,
|
|
467
|
-
router
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
expect(result).toBe(to);
|
|
471
|
-
expect(to.handle).toBeTypeOf('function');
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
it('should pass the correct to and from parameters to tasks', async () => {
|
|
475
|
-
const router = createMockRouter();
|
|
476
|
-
const to = new Route({
|
|
477
|
-
options: router.parsedOptions,
|
|
478
|
-
toType: RouteType.push,
|
|
479
|
-
toInput: '/test'
|
|
480
|
-
});
|
|
481
|
-
const from = new Route({
|
|
482
|
-
options: router.parsedOptions,
|
|
483
|
-
toType: RouteType.push,
|
|
484
|
-
toInput: '/home'
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
const firstTask = async (
|
|
488
|
-
route: Route,
|
|
489
|
-
fromRoute: Route | null,
|
|
490
|
-
router: Router
|
|
491
|
-
) => {
|
|
492
|
-
expect(route).toBe(to);
|
|
493
|
-
expect(fromRoute).toBe(from);
|
|
494
|
-
return;
|
|
495
|
-
};
|
|
496
|
-
|
|
497
|
-
const secondTask = async (
|
|
498
|
-
route: Route,
|
|
499
|
-
fromRoute: Route | null,
|
|
500
|
-
router: Router
|
|
501
|
-
): Promise<false> => {
|
|
502
|
-
expect(route).toBe(to);
|
|
503
|
-
expect(fromRoute).toBe(from);
|
|
504
|
-
return false; // Abort the task.
|
|
505
|
-
};
|
|
506
|
-
|
|
507
|
-
const thirdTask = async (
|
|
508
|
-
route: Route,
|
|
509
|
-
fromRoute: Route | null,
|
|
510
|
-
router: Router
|
|
511
|
-
) => {
|
|
512
|
-
throw new Error('This should not be executed');
|
|
513
|
-
};
|
|
514
|
-
|
|
515
|
-
const tasks: RouteTask[] = [
|
|
516
|
-
{
|
|
517
|
-
name: 'beforeEach',
|
|
518
|
-
task: firstTask
|
|
519
|
-
},
|
|
520
|
-
{
|
|
521
|
-
name: 'beforeEnter',
|
|
522
|
-
task: secondTask
|
|
523
|
-
},
|
|
524
|
-
{
|
|
525
|
-
name: 'confirm',
|
|
526
|
-
task: thirdTask
|
|
527
|
-
}
|
|
528
|
-
];
|
|
529
|
-
|
|
530
|
-
// Task returning false should throw RouteNavigationAbortedError
|
|
531
|
-
await expect(
|
|
532
|
-
createRouteTask({
|
|
533
|
-
to,
|
|
534
|
-
from,
|
|
535
|
-
tasks,
|
|
536
|
-
router
|
|
537
|
-
})
|
|
538
|
-
).rejects.toThrow(RouteNavigationAbortedError);
|
|
539
|
-
});
|
|
540
|
-
|
|
541
|
-
it('should execute all tasks until one returns a result', async () => {
|
|
542
|
-
const router = createMockRouter();
|
|
543
|
-
const to = new Route({
|
|
544
|
-
options: router.parsedOptions,
|
|
545
|
-
toType: RouteType.push,
|
|
546
|
-
toInput: '/test'
|
|
547
|
-
});
|
|
548
|
-
const from = new Route({
|
|
549
|
-
options: router.parsedOptions,
|
|
550
|
-
toType: RouteType.push,
|
|
551
|
-
toInput: '/home'
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
const executionOrder: string[] = [];
|
|
555
|
-
|
|
556
|
-
const firstTask = async (
|
|
557
|
-
route: Route,
|
|
558
|
-
fromRoute: Route | null,
|
|
559
|
-
router: Router
|
|
560
|
-
) => {
|
|
561
|
-
executionOrder.push('task1');
|
|
562
|
-
return; // Continue execution.
|
|
563
|
-
};
|
|
564
|
-
|
|
565
|
-
const handleFunction = async (
|
|
566
|
-
to: Route,
|
|
567
|
-
from: Route | null,
|
|
568
|
-
router: Router
|
|
569
|
-
) => {
|
|
570
|
-
return { message: 'Route handled' };
|
|
571
|
-
};
|
|
572
|
-
|
|
573
|
-
const secondTask = async (
|
|
574
|
-
route: Route,
|
|
575
|
-
fromRoute: Route | null,
|
|
576
|
-
router: Router
|
|
577
|
-
) => {
|
|
578
|
-
executionOrder.push('task2');
|
|
579
|
-
return handleFunction; // Return handler function and terminate execution.
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
const thirdTask = async (
|
|
583
|
-
route: Route,
|
|
584
|
-
fromRoute: Route | null,
|
|
585
|
-
router: Router
|
|
586
|
-
) => {
|
|
587
|
-
executionOrder.push('task3'); // This should NOT be executed.
|
|
588
|
-
return;
|
|
589
|
-
};
|
|
590
|
-
|
|
591
|
-
const tasks: RouteTask[] = [
|
|
592
|
-
{
|
|
593
|
-
name: 'beforeEach',
|
|
594
|
-
task: firstTask
|
|
595
|
-
},
|
|
596
|
-
{
|
|
597
|
-
name: 'beforeEnter',
|
|
598
|
-
task: secondTask
|
|
599
|
-
},
|
|
600
|
-
{
|
|
601
|
-
name: 'confirm',
|
|
602
|
-
task: thirdTask
|
|
603
|
-
}
|
|
604
|
-
];
|
|
605
|
-
|
|
606
|
-
const result = await createRouteTask({
|
|
607
|
-
to,
|
|
608
|
-
from,
|
|
609
|
-
tasks,
|
|
610
|
-
router
|
|
611
|
-
});
|
|
612
|
-
|
|
613
|
-
expect(result).toBe(to);
|
|
614
|
-
// After removing RouteStatus, we check for successful handle instead of success status
|
|
615
|
-
expect(to.handle).toBeTypeOf('function');
|
|
616
|
-
expect(to.handle).not.toBe(null);
|
|
617
|
-
expect(executionOrder).toEqual(['task1', 'task2']); // Only the first two tasks should be executed.
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
describe('Task cancellation with RouteTaskController', () => {
|
|
621
|
-
it('should cancel task when abort is called before task execution', async () => {
|
|
622
|
-
const router = createMockRouter();
|
|
623
|
-
const to = new Route({
|
|
624
|
-
options: router.parsedOptions,
|
|
625
|
-
toType: RouteType.push,
|
|
626
|
-
toInput: '/test'
|
|
627
|
-
});
|
|
628
|
-
const from = new Route({
|
|
629
|
-
options: router.parsedOptions,
|
|
630
|
-
toType: RouteType.push,
|
|
631
|
-
toInput: '/home'
|
|
632
|
-
});
|
|
633
|
-
|
|
634
|
-
const controller = new RouteTaskController();
|
|
635
|
-
|
|
636
|
-
const firstTask = async (
|
|
637
|
-
route: Route,
|
|
638
|
-
fromRoute: Route | null,
|
|
639
|
-
router: Router
|
|
640
|
-
) => {
|
|
641
|
-
throw new Error('This should not be executed');
|
|
642
|
-
};
|
|
643
|
-
|
|
644
|
-
const secondTask = async (
|
|
645
|
-
route: Route,
|
|
646
|
-
fromRoute: Route | null,
|
|
647
|
-
router: Router
|
|
648
|
-
) => {
|
|
649
|
-
throw new Error('This should also not be executed');
|
|
650
|
-
};
|
|
651
|
-
|
|
652
|
-
const tasks: RouteTask[] = [
|
|
653
|
-
{
|
|
654
|
-
name: 'beforeEach',
|
|
655
|
-
task: firstTask
|
|
656
|
-
},
|
|
657
|
-
{
|
|
658
|
-
name: 'beforeEnter',
|
|
659
|
-
task: secondTask
|
|
660
|
-
}
|
|
661
|
-
];
|
|
662
|
-
|
|
663
|
-
// Cancel before execution starts.
|
|
664
|
-
controller.abort();
|
|
665
|
-
|
|
666
|
-
await expect(
|
|
667
|
-
createRouteTask({
|
|
668
|
-
to,
|
|
669
|
-
from,
|
|
670
|
-
tasks,
|
|
671
|
-
controller,
|
|
672
|
-
router
|
|
673
|
-
})
|
|
674
|
-
).rejects.toThrow(RouteTaskCancelledError);
|
|
675
|
-
});
|
|
676
|
-
|
|
677
|
-
it('should cancel task when abort is called after first task execution', async () => {
|
|
678
|
-
const router = createMockRouter();
|
|
679
|
-
const to = new Route({
|
|
680
|
-
options: router.parsedOptions,
|
|
681
|
-
toType: RouteType.push,
|
|
682
|
-
toInput: '/test'
|
|
683
|
-
});
|
|
684
|
-
const from = new Route({
|
|
685
|
-
options: router.parsedOptions,
|
|
686
|
-
toType: RouteType.push,
|
|
687
|
-
toInput: '/home'
|
|
688
|
-
});
|
|
689
|
-
|
|
690
|
-
const controller = new RouteTaskController();
|
|
691
|
-
|
|
692
|
-
const firstTask = async (
|
|
693
|
-
route: Route,
|
|
694
|
-
fromRoute: Route | null,
|
|
695
|
-
router: Router
|
|
696
|
-
) => {
|
|
697
|
-
controller.abort(); // Cancel after first task completes.
|
|
698
|
-
return; // Continue execution.
|
|
699
|
-
};
|
|
700
|
-
|
|
701
|
-
const secondTask = async (
|
|
702
|
-
route: Route,
|
|
703
|
-
fromRoute: Route | null,
|
|
704
|
-
router: Router
|
|
705
|
-
) => {
|
|
706
|
-
throw new Error('This should not be executed');
|
|
707
|
-
};
|
|
708
|
-
|
|
709
|
-
const tasks: RouteTask[] = [
|
|
710
|
-
{
|
|
711
|
-
name: 'beforeEach',
|
|
712
|
-
task: firstTask
|
|
713
|
-
},
|
|
714
|
-
{
|
|
715
|
-
name: 'beforeEnter',
|
|
716
|
-
task: secondTask
|
|
717
|
-
}
|
|
718
|
-
];
|
|
719
|
-
|
|
720
|
-
await expect(
|
|
721
|
-
createRouteTask({
|
|
722
|
-
to,
|
|
723
|
-
from,
|
|
724
|
-
tasks,
|
|
725
|
-
controller,
|
|
726
|
-
router
|
|
727
|
-
})
|
|
728
|
-
).rejects.toThrow(RouteTaskCancelledError);
|
|
729
|
-
});
|
|
730
|
-
|
|
731
|
-
it('should not throw error on shouldCancel if controller is provided', async () => {
|
|
732
|
-
const router = createMockRouter();
|
|
733
|
-
const to = new Route({
|
|
734
|
-
options: router.parsedOptions,
|
|
735
|
-
toType: RouteType.push,
|
|
736
|
-
toInput: '/test'
|
|
737
|
-
});
|
|
738
|
-
const from = new Route({
|
|
739
|
-
options: router.parsedOptions,
|
|
740
|
-
toType: RouteType.push,
|
|
741
|
-
toInput: '/home'
|
|
742
|
-
});
|
|
743
|
-
|
|
744
|
-
const handleTask = async (
|
|
745
|
-
route: Route,
|
|
746
|
-
fromRoute: Route | null,
|
|
747
|
-
router: Router
|
|
748
|
-
) => {
|
|
749
|
-
return async () => ({ success: true }); // Return handle function instead of redirecting
|
|
750
|
-
};
|
|
751
|
-
|
|
752
|
-
const tasks: RouteTask[] = [
|
|
753
|
-
{
|
|
754
|
-
name: 'beforeEach',
|
|
755
|
-
task: handleTask
|
|
756
|
-
}
|
|
757
|
-
];
|
|
758
|
-
|
|
759
|
-
// No controller provided
|
|
760
|
-
const result = await createRouteTask({
|
|
761
|
-
to,
|
|
762
|
-
from,
|
|
763
|
-
tasks,
|
|
764
|
-
router
|
|
765
|
-
});
|
|
766
|
-
|
|
767
|
-
expect(result).toBe(to);
|
|
768
|
-
expect(result?.handle).toBeTypeOf('function');
|
|
769
|
-
});
|
|
770
|
-
});
|
|
771
|
-
|
|
772
|
-
describe('Real scenario test', () => {
|
|
773
|
-
it('should correctly handle RouteTaskOptions type verification', async () => {
|
|
774
|
-
const router = createMockRouter();
|
|
775
|
-
const to = new Route({
|
|
776
|
-
options: router.parsedOptions,
|
|
777
|
-
toType: RouteType.push,
|
|
778
|
-
toInput: '/test'
|
|
779
|
-
});
|
|
780
|
-
const from = new Route({
|
|
781
|
-
options: router.parsedOptions,
|
|
782
|
-
toType: RouteType.push,
|
|
783
|
-
toInput: '/home'
|
|
784
|
-
});
|
|
785
|
-
|
|
786
|
-
const tasks: RouteTask[] = [];
|
|
787
|
-
|
|
788
|
-
const routeTaskOptions: RouteTaskOptions = {
|
|
789
|
-
to,
|
|
790
|
-
from,
|
|
791
|
-
tasks,
|
|
792
|
-
router
|
|
793
|
-
};
|
|
794
|
-
|
|
795
|
-
const result = await createRouteTask(routeTaskOptions);
|
|
796
|
-
expect(result).toBe(to);
|
|
797
|
-
});
|
|
798
|
-
|
|
799
|
-
it('should correctly handle RouteTaskOptions with controller', async () => {
|
|
800
|
-
const router = createMockRouter();
|
|
801
|
-
const to = new Route({
|
|
802
|
-
options: router.parsedOptions,
|
|
803
|
-
toType: RouteType.push,
|
|
804
|
-
toInput: '/test'
|
|
805
|
-
});
|
|
806
|
-
const from = new Route({
|
|
807
|
-
options: router.parsedOptions,
|
|
808
|
-
toType: RouteType.push,
|
|
809
|
-
toInput: '/home'
|
|
810
|
-
});
|
|
811
|
-
|
|
812
|
-
const tasks: RouteTask[] = [];
|
|
813
|
-
const controller = new RouteTaskController();
|
|
814
|
-
|
|
815
|
-
const routeTaskOptions: RouteTaskOptions = {
|
|
816
|
-
to,
|
|
817
|
-
from,
|
|
818
|
-
tasks,
|
|
819
|
-
router,
|
|
820
|
-
controller
|
|
821
|
-
};
|
|
822
|
-
|
|
823
|
-
const result = await createRouteTask(routeTaskOptions);
|
|
824
|
-
expect(result).toBe(to);
|
|
825
|
-
});
|
|
826
|
-
|
|
827
|
-
it('should correctly create real task function interface', async () => {
|
|
828
|
-
const router = createMockRouter();
|
|
829
|
-
const to = new Route({
|
|
830
|
-
options: router.parsedOptions,
|
|
831
|
-
toType: RouteType.push,
|
|
832
|
-
toInput: '/test'
|
|
833
|
-
});
|
|
834
|
-
const from = new Route({
|
|
835
|
-
options: router.parsedOptions,
|
|
836
|
-
toType: RouteType.push,
|
|
837
|
-
toInput: '/home'
|
|
838
|
-
});
|
|
839
|
-
|
|
840
|
-
const realTaskFunction = async (
|
|
841
|
-
route: Route,
|
|
842
|
-
fromRoute: Route | null,
|
|
843
|
-
router: Router
|
|
844
|
-
) => {
|
|
845
|
-
// Test parameter types
|
|
846
|
-
expect(route).toBeInstanceOf(Route);
|
|
847
|
-
expect(fromRoute).toBeInstanceOf(Route);
|
|
848
|
-
expect(router).toBeDefined();
|
|
849
|
-
return async () => ({ success: true }); // Return handler
|
|
850
|
-
};
|
|
851
|
-
|
|
852
|
-
const tasks: RouteTask[] = [
|
|
853
|
-
{
|
|
854
|
-
name: 'beforeEach',
|
|
855
|
-
task: realTaskFunction
|
|
856
|
-
}
|
|
857
|
-
];
|
|
858
|
-
|
|
859
|
-
const result = await createRouteTask({
|
|
860
|
-
to,
|
|
861
|
-
from,
|
|
862
|
-
tasks,
|
|
863
|
-
router
|
|
864
|
-
});
|
|
865
|
-
|
|
866
|
-
expect(result).toBe(to);
|
|
867
|
-
expect(to.handle).toBeTypeOf('function');
|
|
868
|
-
});
|
|
869
|
-
});
|
|
870
|
-
});
|
|
871
|
-
|
|
872
|
-
describe('RouteTaskController', () => {
|
|
873
|
-
it('should handle task cancellation', async () => {
|
|
874
|
-
const router = createMockRouter();
|
|
875
|
-
const to = new Route({
|
|
876
|
-
options: router.parsedOptions,
|
|
877
|
-
toType: RouteType.push,
|
|
878
|
-
toInput: '/test'
|
|
879
|
-
});
|
|
880
|
-
const controller = new RouteTaskController();
|
|
881
|
-
|
|
882
|
-
controller.abort();
|
|
883
|
-
|
|
884
|
-
const tasks: RouteTask[] = [
|
|
885
|
-
{
|
|
886
|
-
name: 'beforeEach',
|
|
887
|
-
task: async () => async () => ({ success: true })
|
|
888
|
-
}
|
|
889
|
-
];
|
|
890
|
-
|
|
891
|
-
await expect(
|
|
892
|
-
createRouteTask({
|
|
893
|
-
to,
|
|
894
|
-
from: null,
|
|
895
|
-
tasks,
|
|
896
|
-
router,
|
|
897
|
-
controller
|
|
898
|
-
})
|
|
899
|
-
).rejects.toThrow(RouteTaskCancelledError);
|
|
900
|
-
});
|
|
901
|
-
});
|