@esmx/router-vue 3.0.0-rc.17 → 3.0.0-rc.19
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 +1 -1
- package/README.md +563 -0
- package/README.zh-CN.md +563 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.mjs +11 -4
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.mjs +206 -0
- package/dist/plugin.d.ts +55 -11
- package/dist/plugin.mjs +32 -16
- package/dist/plugin.test.d.ts +1 -0
- package/dist/plugin.test.mjs +436 -0
- package/dist/router-link.d.ts +202 -0
- package/dist/router-link.mjs +84 -0
- package/dist/router-link.test.d.ts +1 -0
- package/dist/router-link.test.mjs +456 -0
- package/dist/router-view.d.ts +30 -0
- package/dist/router-view.mjs +17 -0
- package/dist/router-view.test.d.ts +1 -0
- package/dist/router-view.test.mjs +459 -0
- package/dist/use.d.ts +198 -3
- package/dist/use.mjs +75 -9
- package/dist/use.test.d.ts +1 -0
- package/dist/use.test.mjs +461 -0
- package/dist/util.d.ts +7 -0
- package/dist/util.mjs +24 -0
- package/dist/util.test.d.ts +1 -0
- package/dist/util.test.mjs +319 -0
- package/dist/vue2.d.ts +13 -0
- package/dist/vue2.mjs +0 -0
- package/dist/vue3.d.ts +13 -0
- package/dist/vue3.mjs +0 -0
- package/package.json +31 -14
- package/src/index.test.ts +263 -0
- package/src/index.ts +16 -4
- package/src/plugin.test.ts +574 -0
- package/src/plugin.ts +86 -31
- package/src/router-link.test.ts +569 -0
- package/src/router-link.ts +148 -0
- package/src/router-view.test.ts +599 -0
- package/src/router-view.ts +61 -0
- package/src/use.test.ts +616 -0
- package/src/use.ts +307 -11
- package/src/util.test.ts +418 -0
- package/src/util.ts +32 -0
- package/src/vue2.ts +16 -0
- package/src/vue3.ts +15 -0
- package/dist/link.d.ts +0 -101
- package/dist/link.mjs +0 -103
- package/dist/symbols.d.ts +0 -3
- package/dist/symbols.mjs +0 -3
- package/dist/view.d.ts +0 -21
- package/dist/view.mjs +0 -75
- package/src/link.ts +0 -177
- package/src/symbols.ts +0 -8
- package/src/view.ts +0 -95
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { version } from "vue";
|
|
3
|
+
import {
|
|
4
|
+
createSymbolProperty,
|
|
5
|
+
isESModule,
|
|
6
|
+
isVue3,
|
|
7
|
+
resolveComponent
|
|
8
|
+
} from "./util.mjs";
|
|
9
|
+
describe("util.ts - Utility Functions", () => {
|
|
10
|
+
describe("isVue3", () => {
|
|
11
|
+
it("should correctly identify Vue 3", () => {
|
|
12
|
+
expect(isVue3).toBe(version.startsWith("3."));
|
|
13
|
+
expect(typeof isVue3).toBe("boolean");
|
|
14
|
+
});
|
|
15
|
+
it("should be consistent with Vue version check", () => {
|
|
16
|
+
const expectedResult = version.startsWith("3.");
|
|
17
|
+
expect(isVue3).toBe(expectedResult);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
describe("createSymbolProperty", () => {
|
|
21
|
+
let testSymbol;
|
|
22
|
+
let symbolProperty;
|
|
23
|
+
let testInstance;
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
testSymbol = Symbol("test-symbol");
|
|
26
|
+
symbolProperty = createSymbolProperty(testSymbol);
|
|
27
|
+
testInstance = {};
|
|
28
|
+
});
|
|
29
|
+
describe("set method", () => {
|
|
30
|
+
it("should set value using symbol as key", () => {
|
|
31
|
+
const testValue = "test-value";
|
|
32
|
+
symbolProperty.set(testInstance, testValue);
|
|
33
|
+
expect(testInstance[testSymbol]).toBe(testValue);
|
|
34
|
+
});
|
|
35
|
+
it("should handle different value types", () => {
|
|
36
|
+
const stringValue = "string-value";
|
|
37
|
+
const numberValue = 42;
|
|
38
|
+
const objectValue = { key: "value" };
|
|
39
|
+
const arrayValue = [1, 2, 3];
|
|
40
|
+
const stringProperty = createSymbolProperty(
|
|
41
|
+
Symbol("string")
|
|
42
|
+
);
|
|
43
|
+
const numberProperty = createSymbolProperty(
|
|
44
|
+
Symbol("number")
|
|
45
|
+
);
|
|
46
|
+
const objectProperty = createSymbolProperty(
|
|
47
|
+
Symbol("object")
|
|
48
|
+
);
|
|
49
|
+
const arrayProperty = createSymbolProperty(
|
|
50
|
+
Symbol("array")
|
|
51
|
+
);
|
|
52
|
+
stringProperty.set(testInstance, stringValue);
|
|
53
|
+
numberProperty.set(testInstance, numberValue);
|
|
54
|
+
objectProperty.set(testInstance, objectValue);
|
|
55
|
+
arrayProperty.set(testInstance, arrayValue);
|
|
56
|
+
expect(stringProperty.get(testInstance)).toBe(stringValue);
|
|
57
|
+
expect(numberProperty.get(testInstance)).toBe(numberValue);
|
|
58
|
+
expect(objectProperty.get(testInstance)).toBe(objectValue);
|
|
59
|
+
expect(arrayProperty.get(testInstance)).toBe(arrayValue);
|
|
60
|
+
});
|
|
61
|
+
it("should overwrite existing value", () => {
|
|
62
|
+
const firstValue = "first-value";
|
|
63
|
+
const secondValue = "second-value";
|
|
64
|
+
symbolProperty.set(testInstance, firstValue);
|
|
65
|
+
expect(symbolProperty.get(testInstance)).toBe(firstValue);
|
|
66
|
+
symbolProperty.set(testInstance, secondValue);
|
|
67
|
+
expect(symbolProperty.get(testInstance)).toBe(secondValue);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe("get method", () => {
|
|
71
|
+
it("should return undefined for non-existent symbol", () => {
|
|
72
|
+
const result = symbolProperty.get(testInstance);
|
|
73
|
+
expect(result).toBeUndefined();
|
|
74
|
+
});
|
|
75
|
+
it("should return correct value after setting", () => {
|
|
76
|
+
const testValue = "retrieved-value";
|
|
77
|
+
symbolProperty.set(testInstance, testValue);
|
|
78
|
+
const result = symbolProperty.get(testInstance);
|
|
79
|
+
expect(result).toBe(testValue);
|
|
80
|
+
});
|
|
81
|
+
it("should return undefined after value is deleted", () => {
|
|
82
|
+
const testValue = "temporary-value";
|
|
83
|
+
symbolProperty.set(testInstance, testValue);
|
|
84
|
+
delete testInstance[testSymbol];
|
|
85
|
+
const result = symbolProperty.get(testInstance);
|
|
86
|
+
expect(result).toBeUndefined();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe("symbol isolation", () => {
|
|
90
|
+
it("should not interfere with different symbols", () => {
|
|
91
|
+
const symbol1 = Symbol("symbol1");
|
|
92
|
+
const symbol2 = Symbol("symbol2");
|
|
93
|
+
const property1 = createSymbolProperty(symbol1);
|
|
94
|
+
const property2 = createSymbolProperty(symbol2);
|
|
95
|
+
const value1 = "value1";
|
|
96
|
+
const value2 = "value2";
|
|
97
|
+
property1.set(testInstance, value1);
|
|
98
|
+
property2.set(testInstance, value2);
|
|
99
|
+
expect(property1.get(testInstance)).toBe(value1);
|
|
100
|
+
expect(property2.get(testInstance)).toBe(value2);
|
|
101
|
+
expect(property1.get(testInstance)).not.toBe(value2);
|
|
102
|
+
expect(property2.get(testInstance)).not.toBe(value1);
|
|
103
|
+
});
|
|
104
|
+
it("should work with multiple instances", () => {
|
|
105
|
+
const instance1 = {};
|
|
106
|
+
const instance2 = {};
|
|
107
|
+
const testValue1 = "instance1-value";
|
|
108
|
+
const testValue2 = "instance2-value";
|
|
109
|
+
symbolProperty.set(instance1, testValue1);
|
|
110
|
+
symbolProperty.set(instance2, testValue2);
|
|
111
|
+
expect(symbolProperty.get(instance1)).toBe(testValue1);
|
|
112
|
+
expect(symbolProperty.get(instance2)).toBe(testValue2);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe("type safety", () => {
|
|
116
|
+
it("should maintain type information through generic", () => {
|
|
117
|
+
const interfaceSymbol = Symbol("interface");
|
|
118
|
+
const interfaceProperty = createSymbolProperty(interfaceSymbol);
|
|
119
|
+
const testObject = { name: "test", count: 5 };
|
|
120
|
+
interfaceProperty.set(testInstance, testObject);
|
|
121
|
+
const result = interfaceProperty.get(testInstance);
|
|
122
|
+
expect(result).toEqual(testObject);
|
|
123
|
+
expect(result == null ? void 0 : result.name).toBe("test");
|
|
124
|
+
expect(result == null ? void 0 : result.count).toBe(5);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
describe("isESModule", () => {
|
|
129
|
+
describe("should return true for ES modules", () => {
|
|
130
|
+
it("should identify module with __esModule property", () => {
|
|
131
|
+
const esModule = { __esModule: true };
|
|
132
|
+
expect(isESModule(esModule)).toBe(true);
|
|
133
|
+
});
|
|
134
|
+
it("should identify module with Symbol.toStringTag", () => {
|
|
135
|
+
const esModule = { [Symbol.toStringTag]: "Module" };
|
|
136
|
+
expect(isESModule(esModule)).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
it("should identify module with both properties", () => {
|
|
139
|
+
const esModule = {
|
|
140
|
+
__esModule: true,
|
|
141
|
+
[Symbol.toStringTag]: "Module"
|
|
142
|
+
};
|
|
143
|
+
expect(isESModule(esModule)).toBe(true);
|
|
144
|
+
});
|
|
145
|
+
it("should handle truthy __esModule values", () => {
|
|
146
|
+
const testCases = [
|
|
147
|
+
{ __esModule: true },
|
|
148
|
+
{ __esModule: 1 },
|
|
149
|
+
{ __esModule: "true" },
|
|
150
|
+
{ __esModule: {} },
|
|
151
|
+
{ __esModule: [] }
|
|
152
|
+
];
|
|
153
|
+
testCases.forEach((moduleObj) => {
|
|
154
|
+
expect(isESModule(moduleObj)).toBe(true);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
describe("should return false for non-ES modules", () => {
|
|
159
|
+
it("should return false for null", () => {
|
|
160
|
+
expect(isESModule(null)).toBe(false);
|
|
161
|
+
});
|
|
162
|
+
it("should return false for undefined", () => {
|
|
163
|
+
expect(isESModule(void 0)).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
it("should return false for plain objects", () => {
|
|
166
|
+
const plainObject = { key: "value" };
|
|
167
|
+
expect(isESModule(plainObject)).toBe(false);
|
|
168
|
+
});
|
|
169
|
+
it("should return false for objects with falsy __esModule", () => {
|
|
170
|
+
const testCases = [
|
|
171
|
+
{ __esModule: false },
|
|
172
|
+
{ __esModule: 0 },
|
|
173
|
+
{ __esModule: "" },
|
|
174
|
+
{ __esModule: null },
|
|
175
|
+
{ __esModule: void 0 }
|
|
176
|
+
];
|
|
177
|
+
testCases.forEach((moduleObj) => {
|
|
178
|
+
expect(isESModule(moduleObj)).toBe(false);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
it("should return false for objects with wrong Symbol.toStringTag", () => {
|
|
182
|
+
const testCases = [
|
|
183
|
+
{ [Symbol.toStringTag]: "Object" },
|
|
184
|
+
{ [Symbol.toStringTag]: "Function" },
|
|
185
|
+
{ [Symbol.toStringTag]: "Array" },
|
|
186
|
+
{ [Symbol.toStringTag]: "" },
|
|
187
|
+
{ [Symbol.toStringTag]: null }
|
|
188
|
+
];
|
|
189
|
+
testCases.forEach((moduleObj) => {
|
|
190
|
+
expect(isESModule(moduleObj)).toBe(false);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
it("should return false for primitive values", () => {
|
|
194
|
+
const primitives = ["string", 42, true, false, Symbol("test")];
|
|
195
|
+
primitives.forEach((primitive) => {
|
|
196
|
+
expect(isESModule(primitive)).toBe(false);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
describe("resolveComponent", () => {
|
|
202
|
+
describe("should return null for falsy inputs", () => {
|
|
203
|
+
const falsyValues = [null, void 0, false, 0, "", Number.NaN];
|
|
204
|
+
falsyValues.forEach((value) => {
|
|
205
|
+
it(`should return null for ${value}`, () => {
|
|
206
|
+
expect(resolveComponent(value)).toBeNull();
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
describe("should handle ES modules", () => {
|
|
211
|
+
it("should return default export when available", () => {
|
|
212
|
+
const defaultComponent = { name: "DefaultComponent" };
|
|
213
|
+
const esModule = {
|
|
214
|
+
__esModule: true,
|
|
215
|
+
default: defaultComponent,
|
|
216
|
+
namedExport: { name: "NamedComponent" }
|
|
217
|
+
};
|
|
218
|
+
const result = resolveComponent(esModule);
|
|
219
|
+
expect(result).toBe(defaultComponent);
|
|
220
|
+
});
|
|
221
|
+
it("should return the module itself when no default export", () => {
|
|
222
|
+
const esModule = {
|
|
223
|
+
__esModule: true,
|
|
224
|
+
namedExport: { name: "NamedComponent" }
|
|
225
|
+
};
|
|
226
|
+
const result = resolveComponent(esModule);
|
|
227
|
+
expect(result).toBe(esModule);
|
|
228
|
+
});
|
|
229
|
+
it("should prefer default export over module when both exist", () => {
|
|
230
|
+
const defaultComponent = { name: "DefaultComponent" };
|
|
231
|
+
const esModule = {
|
|
232
|
+
__esModule: true,
|
|
233
|
+
default: defaultComponent,
|
|
234
|
+
name: "ModuleComponent"
|
|
235
|
+
};
|
|
236
|
+
const result = resolveComponent(esModule);
|
|
237
|
+
expect(result).toBe(defaultComponent);
|
|
238
|
+
expect(result).not.toBe(esModule);
|
|
239
|
+
});
|
|
240
|
+
it("should handle modules with Symbol.toStringTag", () => {
|
|
241
|
+
const defaultComponent = { name: "SymbolTagComponent" };
|
|
242
|
+
const esModule = {
|
|
243
|
+
[Symbol.toStringTag]: "Module",
|
|
244
|
+
default: defaultComponent
|
|
245
|
+
};
|
|
246
|
+
const result = resolveComponent(esModule);
|
|
247
|
+
expect(result).toBe(defaultComponent);
|
|
248
|
+
});
|
|
249
|
+
it("should handle falsy default export", () => {
|
|
250
|
+
const falsyDefaults = [null, void 0, false, 0, ""];
|
|
251
|
+
falsyDefaults.forEach((falsyDefault) => {
|
|
252
|
+
const esModule = {
|
|
253
|
+
__esModule: true,
|
|
254
|
+
default: falsyDefault,
|
|
255
|
+
fallback: { name: "FallbackComponent" }
|
|
256
|
+
};
|
|
257
|
+
const result = resolveComponent(esModule);
|
|
258
|
+
expect(result).toBe(esModule);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
describe("should handle non-ES modules", () => {
|
|
263
|
+
it("should return component directly for non-ES modules", () => {
|
|
264
|
+
const component = { name: "RegularComponent" };
|
|
265
|
+
const result = resolveComponent(component);
|
|
266
|
+
expect(result).toBe(component);
|
|
267
|
+
});
|
|
268
|
+
it("should return function components directly", () => {
|
|
269
|
+
const functionComponent = () => ({ name: "FunctionComponent" });
|
|
270
|
+
const result = resolveComponent(functionComponent);
|
|
271
|
+
expect(result).toBe(functionComponent);
|
|
272
|
+
});
|
|
273
|
+
it("should return class components directly", () => {
|
|
274
|
+
class ClassComponent {
|
|
275
|
+
name = "ClassComponent";
|
|
276
|
+
}
|
|
277
|
+
const result = resolveComponent(ClassComponent);
|
|
278
|
+
expect(result).toBe(ClassComponent);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
describe("edge cases", () => {
|
|
282
|
+
it("should handle circular references in modules", () => {
|
|
283
|
+
const esModule = {
|
|
284
|
+
__esModule: true
|
|
285
|
+
};
|
|
286
|
+
esModule.default = esModule;
|
|
287
|
+
const result = resolveComponent(esModule);
|
|
288
|
+
expect(result).toBe(esModule);
|
|
289
|
+
});
|
|
290
|
+
it("should handle deeply nested default exports", () => {
|
|
291
|
+
const actualComponent = { name: "DeepComponent" };
|
|
292
|
+
const esModule = {
|
|
293
|
+
__esModule: true,
|
|
294
|
+
default: {
|
|
295
|
+
default: {
|
|
296
|
+
default: actualComponent
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
const result = resolveComponent(esModule);
|
|
301
|
+
expect(result).toEqual({
|
|
302
|
+
default: {
|
|
303
|
+
default: actualComponent
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
it("should handle modules with both __esModule and Symbol.toStringTag", () => {
|
|
308
|
+
const defaultComponent = { name: "BothPropertiesComponent" };
|
|
309
|
+
const esModule = {
|
|
310
|
+
__esModule: true,
|
|
311
|
+
[Symbol.toStringTag]: "Module",
|
|
312
|
+
default: defaultComponent
|
|
313
|
+
};
|
|
314
|
+
const result = resolveComponent(esModule);
|
|
315
|
+
expect(result).toBe(defaultComponent);
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
});
|
package/dist/vue2.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Route, Router } from '@esmx/router';
|
|
2
|
+
declare module 'vue/types/vue' {
|
|
3
|
+
interface Vue {
|
|
4
|
+
readonly $router: Router;
|
|
5
|
+
readonly $route: Route;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
declare module 'vue2/types/vue' {
|
|
9
|
+
interface Vue {
|
|
10
|
+
readonly $router: Router;
|
|
11
|
+
readonly $route: Route;
|
|
12
|
+
}
|
|
13
|
+
}
|
package/dist/vue2.mjs
ADDED
|
File without changes
|
package/dist/vue3.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Route, Router } from '@esmx/router';
|
|
2
|
+
import type { RouterLink } from './router-link';
|
|
3
|
+
import type { RouterView } from './router-view';
|
|
4
|
+
declare module 'vue' {
|
|
5
|
+
interface ComponentCustomProperties {
|
|
6
|
+
readonly $router: Router;
|
|
7
|
+
readonly $route: Route;
|
|
8
|
+
}
|
|
9
|
+
interface GlobalComponents {
|
|
10
|
+
RouterLink: typeof RouterLink;
|
|
11
|
+
RouterView: typeof RouterView;
|
|
12
|
+
}
|
|
13
|
+
}
|
package/dist/vue3.mjs
ADDED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@esmx/router-vue",
|
|
3
|
+
"description": "Vue integration for @esmx/router - A universal router that works seamlessly with both Vue 2.7+ and Vue 3",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"vue",
|
|
6
|
+
"router",
|
|
7
|
+
"routing",
|
|
8
|
+
"vue-router",
|
|
9
|
+
"composition-api",
|
|
10
|
+
"typescript",
|
|
11
|
+
"universal",
|
|
12
|
+
"vue2",
|
|
13
|
+
"vue3",
|
|
14
|
+
"navigation",
|
|
15
|
+
"esmx",
|
|
16
|
+
"esm",
|
|
17
|
+
"single-page-application",
|
|
18
|
+
"spa",
|
|
19
|
+
"framework",
|
|
20
|
+
"frontend"
|
|
21
|
+
],
|
|
3
22
|
"template": "library",
|
|
4
23
|
"scripts": {
|
|
5
24
|
"lint:js": "biome check --write --no-errors-on-unmatched",
|
|
@@ -28,26 +47,24 @@
|
|
|
28
47
|
}
|
|
29
48
|
],
|
|
30
49
|
"peerDependencies": {
|
|
31
|
-
"vue": "^3.0.0"
|
|
50
|
+
"vue": "^3.5.0 || ^2.7.0"
|
|
32
51
|
},
|
|
33
52
|
"dependencies": {
|
|
34
|
-
"@esmx/router": "3.0.0-rc.
|
|
53
|
+
"@esmx/router": "3.0.0-rc.19"
|
|
35
54
|
},
|
|
36
55
|
"devDependencies": {
|
|
37
56
|
"@biomejs/biome": "1.9.4",
|
|
38
|
-
"@esmx/lint": "3.0.0-rc.
|
|
39
|
-
"@
|
|
40
|
-
"@
|
|
41
|
-
"
|
|
42
|
-
"@vue/runtime-core": "^3.4.27",
|
|
43
|
-
"@vue/runtime-dom": "^3.4.27",
|
|
44
|
-
"stylelint": "16.15.0",
|
|
57
|
+
"@esmx/lint": "3.0.0-rc.19",
|
|
58
|
+
"@types/node": "22.15.18",
|
|
59
|
+
"@vitest/coverage-v8": "3.1.3",
|
|
60
|
+
"stylelint": "16.19.1",
|
|
45
61
|
"typescript": "5.8.2",
|
|
46
|
-
"unbuild": "
|
|
47
|
-
"vitest": "3.
|
|
48
|
-
"vue": "
|
|
62
|
+
"unbuild": "3.5.0",
|
|
63
|
+
"vitest": "3.1.3",
|
|
64
|
+
"vue": "3.5.13",
|
|
65
|
+
"vue2": "npm:vue@2.7.16"
|
|
49
66
|
},
|
|
50
|
-
"version": "3.0.0-rc.
|
|
67
|
+
"version": "3.0.0-rc.19",
|
|
51
68
|
"type": "module",
|
|
52
69
|
"private": false,
|
|
53
70
|
"exports": {
|
|
@@ -66,5 +83,5 @@
|
|
|
66
83
|
"template",
|
|
67
84
|
"public"
|
|
68
85
|
],
|
|
69
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "83a9cfac4a91b2b54ac576e120bb4541f4cce9d6"
|
|
70
87
|
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment happy-dom
|
|
3
|
+
*/
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import * as RouterVueModule from './index';
|
|
6
|
+
|
|
7
|
+
describe('index.ts - Package Entry Point', () => {
|
|
8
|
+
describe('Composition API Exports', () => {
|
|
9
|
+
it('should export useRouter function', () => {
|
|
10
|
+
expect(RouterVueModule.useRouter).toBeDefined();
|
|
11
|
+
expect(typeof RouterVueModule.useRouter).toBe('function');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should export useRoute function', () => {
|
|
15
|
+
expect(RouterVueModule.useRoute).toBeDefined();
|
|
16
|
+
expect(typeof RouterVueModule.useRoute).toBe('function');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should export useProvideRouter function', () => {
|
|
20
|
+
expect(RouterVueModule.useProvideRouter).toBeDefined();
|
|
21
|
+
expect(typeof RouterVueModule.useProvideRouter).toBe('function');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should export useLink function', () => {
|
|
25
|
+
expect(RouterVueModule.useLink).toBeDefined();
|
|
26
|
+
expect(typeof RouterVueModule.useLink).toBe('function');
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('Options API Exports', () => {
|
|
31
|
+
it('should export getRouter function', () => {
|
|
32
|
+
expect(RouterVueModule.getRouter).toBeDefined();
|
|
33
|
+
expect(typeof RouterVueModule.getRouter).toBe('function');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should export getRoute function', () => {
|
|
37
|
+
expect(RouterVueModule.getRoute).toBeDefined();
|
|
38
|
+
expect(typeof RouterVueModule.getRoute).toBe('function');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('Component Exports', () => {
|
|
43
|
+
it('should export RouterLink component', () => {
|
|
44
|
+
expect(RouterVueModule.RouterLink).toBeDefined();
|
|
45
|
+
expect(typeof RouterVueModule.RouterLink).toBe('object');
|
|
46
|
+
expect(RouterVueModule.RouterLink.name).toBe('RouterLink');
|
|
47
|
+
expect(typeof RouterVueModule.RouterLink.setup).toBe('function');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should export RouterView component', () => {
|
|
51
|
+
expect(RouterVueModule.RouterView).toBeDefined();
|
|
52
|
+
expect(typeof RouterVueModule.RouterView).toBe('object');
|
|
53
|
+
expect(RouterVueModule.RouterView.name).toBe('RouterView');
|
|
54
|
+
expect(typeof RouterVueModule.RouterView.setup).toBe('function');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('Plugin Exports', () => {
|
|
59
|
+
it('should export RouterPlugin', () => {
|
|
60
|
+
expect(RouterVueModule.RouterPlugin).toBeDefined();
|
|
61
|
+
expect(typeof RouterVueModule.RouterPlugin).toBe('object');
|
|
62
|
+
expect(typeof RouterVueModule.RouterPlugin.install).toBe(
|
|
63
|
+
'function'
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('Export Completeness', () => {
|
|
69
|
+
it('should export all expected functions and components', () => {
|
|
70
|
+
const expectedExports = [
|
|
71
|
+
// Composition API
|
|
72
|
+
'useRouter',
|
|
73
|
+
'useRoute',
|
|
74
|
+
'useProvideRouter',
|
|
75
|
+
'useLink',
|
|
76
|
+
// Options API
|
|
77
|
+
'getRouter',
|
|
78
|
+
'getRoute',
|
|
79
|
+
// Components
|
|
80
|
+
'RouterLink',
|
|
81
|
+
'RouterView',
|
|
82
|
+
// Plugin
|
|
83
|
+
'RouterPlugin'
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
expectedExports.forEach((exportName) => {
|
|
87
|
+
expect(RouterVueModule).toHaveProperty(exportName);
|
|
88
|
+
expect(
|
|
89
|
+
RouterVueModule[exportName as keyof typeof RouterVueModule]
|
|
90
|
+
).toBeDefined();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should not export unexpected items', () => {
|
|
95
|
+
const actualExports = Object.keys(RouterVueModule);
|
|
96
|
+
const expectedExports = [
|
|
97
|
+
'useRouter',
|
|
98
|
+
'useRoute',
|
|
99
|
+
'useProvideRouter',
|
|
100
|
+
'useLink',
|
|
101
|
+
'getRouter',
|
|
102
|
+
'getRoute',
|
|
103
|
+
'RouterLink',
|
|
104
|
+
'RouterView',
|
|
105
|
+
'RouterPlugin'
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
// Check that we don't have unexpected exports
|
|
109
|
+
const unexpectedExports = actualExports.filter(
|
|
110
|
+
(exportName) => !expectedExports.includes(exportName)
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
expect(unexpectedExports).toEqual([]);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe('Function Signatures', () => {
|
|
118
|
+
it('should have correct function signatures for Composition API', () => {
|
|
119
|
+
// These should throw expected errors when called without proper context
|
|
120
|
+
expect(() => {
|
|
121
|
+
RouterVueModule.useRouter();
|
|
122
|
+
}).toThrow('useRouter() can only be called during setup()');
|
|
123
|
+
|
|
124
|
+
expect(() => {
|
|
125
|
+
RouterVueModule.useRoute();
|
|
126
|
+
}).toThrow('useRoute() can only be called during setup()');
|
|
127
|
+
|
|
128
|
+
expect(() => {
|
|
129
|
+
RouterVueModule.useLink({
|
|
130
|
+
to: '/test',
|
|
131
|
+
type: 'push',
|
|
132
|
+
exact: 'include'
|
|
133
|
+
});
|
|
134
|
+
}).toThrow('useRouter() can only be called during setup()');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should have correct function signatures for Options API', () => {
|
|
138
|
+
expect(() => {
|
|
139
|
+
try {
|
|
140
|
+
RouterVueModule.getRouter({} as Record<string, unknown>);
|
|
141
|
+
} catch (error: unknown) {
|
|
142
|
+
// Expected to throw context error when called without router
|
|
143
|
+
expect((error as Error).message).toContain(
|
|
144
|
+
'Router context not found'
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
}).not.toThrow();
|
|
148
|
+
|
|
149
|
+
expect(() => {
|
|
150
|
+
try {
|
|
151
|
+
RouterVueModule.getRoute({} as Record<string, unknown>);
|
|
152
|
+
} catch (error: unknown) {
|
|
153
|
+
// Expected to throw context error when called without router
|
|
154
|
+
expect((error as Error).message).toContain(
|
|
155
|
+
'Router context not found'
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}).not.toThrow();
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('Component Properties', () => {
|
|
163
|
+
it('should have RouterLink with correct properties', () => {
|
|
164
|
+
const { RouterLink } = RouterVueModule;
|
|
165
|
+
|
|
166
|
+
expect(RouterLink.name).toBe('RouterLink');
|
|
167
|
+
expect(RouterLink.props).toBeDefined();
|
|
168
|
+
expect(RouterLink.setup).toBeDefined();
|
|
169
|
+
|
|
170
|
+
// Check required props
|
|
171
|
+
expect(RouterLink.props.to).toBeDefined();
|
|
172
|
+
expect(RouterLink.props.to.required).toBe(true);
|
|
173
|
+
|
|
174
|
+
// Check default props
|
|
175
|
+
expect(RouterLink.props.type.default).toBe('push');
|
|
176
|
+
expect(RouterLink.props.exact.default).toBe('include');
|
|
177
|
+
expect(RouterLink.props.tag.default).toBe('a');
|
|
178
|
+
expect(RouterLink.props.event.default).toBe('click');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should have RouterView with correct properties', () => {
|
|
182
|
+
const { RouterView } = RouterVueModule;
|
|
183
|
+
|
|
184
|
+
expect(RouterView.name).toBe('RouterView');
|
|
185
|
+
expect(RouterView.setup).toBeDefined();
|
|
186
|
+
// RouterView should not have props
|
|
187
|
+
expect(RouterView.props).toBeUndefined();
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('Plugin Interface', () => {
|
|
192
|
+
it('should have RouterPlugin with install method', () => {
|
|
193
|
+
const { RouterPlugin } = RouterVueModule;
|
|
194
|
+
|
|
195
|
+
expect(RouterPlugin.install).toBeDefined();
|
|
196
|
+
expect(typeof RouterPlugin.install).toBe('function');
|
|
197
|
+
|
|
198
|
+
// Test plugin install signature - should throw for null input
|
|
199
|
+
expect(() => {
|
|
200
|
+
RouterPlugin.install(null);
|
|
201
|
+
}).toThrow();
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe('Module Structure', () => {
|
|
206
|
+
it('should be a proper ES module', () => {
|
|
207
|
+
// Check that the module exports are properly structured
|
|
208
|
+
expect(typeof RouterVueModule).toBe('object');
|
|
209
|
+
expect(RouterVueModule).not.toBeNull();
|
|
210
|
+
|
|
211
|
+
// Verify it's not a default export
|
|
212
|
+
expect('default' in RouterVueModule).toBe(false);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should have consistent export naming', () => {
|
|
216
|
+
// All function exports should be camelCase
|
|
217
|
+
const functionExports = [
|
|
218
|
+
'useRouter',
|
|
219
|
+
'useRoute',
|
|
220
|
+
'useProvideRouter',
|
|
221
|
+
'useLink',
|
|
222
|
+
'getRouter',
|
|
223
|
+
'getRoute'
|
|
224
|
+
];
|
|
225
|
+
|
|
226
|
+
functionExports.forEach((exportName) => {
|
|
227
|
+
expect(exportName).toMatch(/^[a-z][a-zA-Z]*$/);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Component exports should be PascalCase
|
|
231
|
+
const componentExports = [
|
|
232
|
+
'RouterLink',
|
|
233
|
+
'RouterView',
|
|
234
|
+
'RouterPlugin'
|
|
235
|
+
];
|
|
236
|
+
|
|
237
|
+
componentExports.forEach((exportName) => {
|
|
238
|
+
expect(exportName).toMatch(/^[A-Z][a-zA-Z]*$/);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
describe('TypeScript Integration', () => {
|
|
244
|
+
it('should provide proper TypeScript types', () => {
|
|
245
|
+
// These checks verify that TypeScript types are properly exported
|
|
246
|
+
// The actual type checking is done by the TypeScript compiler
|
|
247
|
+
|
|
248
|
+
// Verify functions have proper types
|
|
249
|
+
expect(typeof RouterVueModule.useRouter).toBe('function');
|
|
250
|
+
expect(typeof RouterVueModule.useRoute).toBe('function');
|
|
251
|
+
expect(typeof RouterVueModule.getRouter).toBe('function');
|
|
252
|
+
expect(typeof RouterVueModule.getRoute).toBe('function');
|
|
253
|
+
|
|
254
|
+
// Verify components have proper structure
|
|
255
|
+
expect(RouterVueModule.RouterLink).toHaveProperty('name');
|
|
256
|
+
expect(RouterVueModule.RouterLink).toHaveProperty('props');
|
|
257
|
+
expect(RouterVueModule.RouterLink).toHaveProperty('setup');
|
|
258
|
+
|
|
259
|
+
expect(RouterVueModule.RouterView).toHaveProperty('name');
|
|
260
|
+
expect(RouterVueModule.RouterView).toHaveProperty('setup');
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
});
|