@immense/vue-pom-generator 1.0.56 → 1.0.58
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.md +1 -1
- package/RELEASE_NOTES.md +32 -12
- package/dist/index.cjs +229 -110
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +229 -110
- package/dist/index.mjs.map +1 -1
- package/dist/method-generation.d.ts.map +1 -1
- package/dist/playwright.config.d.ts.map +1 -1
- package/dist/plugin/nuxt-discovery.d.ts.map +1 -1
- package/dist/plugin/vue-plugin.d.ts.map +1 -1
- package/dist/router-introspection.d.ts.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ export class UserEditorPage extends BasePage {
|
|
|
54
54
|
get SaveButton() { /* Playwright locator */ }
|
|
55
55
|
|
|
56
56
|
async typeEmailAddress(text: string, annotationText = "") { /* ... */ }
|
|
57
|
-
async clickSave(wait: boolean = true) { /* ... */ }
|
|
57
|
+
async clickSave(wait: boolean = true, annotationText = "") { /* ... */ }
|
|
58
58
|
}
|
|
59
59
|
```
|
|
60
60
|
|
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,15 +1,31 @@
|
|
|
1
|
-
●
|
|
1
|
+
● I'll fetch the actual commits and PRs between v1.0.57 and HEAD to generate accurate release
|
|
2
|
+
notes.
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
● Based on the commit range v1.0.57..HEAD, only PR #19 is included in this release. Here are the
|
|
5
|
+
release notes:
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Highlights
|
|
10
|
+
|
|
11
|
+
- Pass annotation text through generated click helpers for better test documentation
|
|
12
|
+
- Resolve Vue compiler and Nuxt kit dependencies from consuming app setups instead of the
|
|
13
|
+
plugin's own tree
|
|
14
|
+
- Centralize Playwright video dimension configuration for consistent local and CI test
|
|
15
|
+
recordings
|
|
6
16
|
|
|
7
17
|
## Changes
|
|
8
18
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
19
|
+
**Local integration hardening:**
|
|
20
|
+
- Generated click helpers now accept and document annotation text parameters
|
|
21
|
+
- Resolve `@vue/compiler-sfc.parse` and `@nuxt/kit` from real consuming-app setups to avoid
|
|
22
|
+
version mismatches
|
|
23
|
+
- Add centralized Playwright video dimensions configuration (`playwright-video-dimensions.json`)
|
|
24
|
+
- Add script to normalize Playwright video settings across local config and CI environments
|
|
25
|
+
|
|
26
|
+
**Test coverage improvements:**
|
|
27
|
+
- Add regression tests for project-local Nuxt kit loading
|
|
28
|
+
- Enhance Nuxt discovery test coverage with real-world integration scenarios
|
|
13
29
|
|
|
14
30
|
## Breaking Changes
|
|
15
31
|
|
|
@@ -17,11 +33,15 @@
|
|
|
17
33
|
|
|
18
34
|
## Pull Requests Included
|
|
19
35
|
|
|
20
|
-
- #
|
|
21
|
-
(https://github.com/immense/vue-pom-generator/pull/17) by @dkattan
|
|
36
|
+
- [#19](https://github.com/immense/vue-pom-generator/pull/19) fix: harden local app integration
|
|
22
37
|
|
|
23
38
|
## Testing
|
|
24
39
|
|
|
25
|
-
|
|
26
|
-
|
|
40
|
+
Validated with:
|
|
41
|
+
- `npm run lint`
|
|
42
|
+
- `npm run typecheck`
|
|
43
|
+
- `npm run build`
|
|
44
|
+
- `npm test`
|
|
45
|
+
|
|
46
|
+
All tests passing with 258 net lines added across 13 files.
|
|
27
47
|
|
package/dist/index.cjs
CHANGED
|
@@ -104,6 +104,21 @@ function createLogger(options) {
|
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
106
|
const requireFromModule = node_module.createRequire(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index.cjs", document.baseURI).href);
|
|
107
|
+
function resolveNuxtKitEntry(cwd) {
|
|
108
|
+
const attemptResolvers = [
|
|
109
|
+
node_module.createRequire(path.resolve(cwd, "package.json")),
|
|
110
|
+
requireFromModule
|
|
111
|
+
];
|
|
112
|
+
let lastError;
|
|
113
|
+
for (const resolver of attemptResolvers) {
|
|
114
|
+
try {
|
|
115
|
+
return resolver.resolve("@nuxt/kit");
|
|
116
|
+
} catch (error) {
|
|
117
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
throw lastError ?? new Error("Unknown module resolution error");
|
|
121
|
+
}
|
|
107
122
|
function toUniqueResolvedPaths(paths) {
|
|
108
123
|
return Array.from(new Set(paths.map((value) => path.resolve(value))));
|
|
109
124
|
}
|
|
@@ -214,7 +229,7 @@ async function loadNuxtProjectDiscovery(cwd = process.cwd()) {
|
|
|
214
229
|
let loadNuxtConfig;
|
|
215
230
|
let getLayerDirectories;
|
|
216
231
|
try {
|
|
217
|
-
const nuxtKitEntry =
|
|
232
|
+
const nuxtKitEntry = resolveNuxtKitEntry(cwd);
|
|
218
233
|
({ loadNuxtConfig, getLayerDirectories } = await import(node_url.pathToFileURL(nuxtKitEntry).href));
|
|
219
234
|
} catch (error) {
|
|
220
235
|
throw new TypeError(
|
|
@@ -403,7 +418,14 @@ function generateClickMethod(methodName, formattedDataTestId, alternateFormatted
|
|
|
403
418
|
const candidatesExpr = [formattedDataTestId, ...alternates].map(testIdExpression).join(", ");
|
|
404
419
|
const clickMethod = createAsyncMethod(
|
|
405
420
|
name,
|
|
406
|
-
hasParam(params, "key") ? [
|
|
421
|
+
hasParam(params, "key") ? [
|
|
422
|
+
...baseParameters,
|
|
423
|
+
createInlineParameter("wait", { type: "boolean", initializer: "true" }),
|
|
424
|
+
createInlineParameter("annotationText", { type: "string", initializer: '""' })
|
|
425
|
+
] : [
|
|
426
|
+
createInlineParameter("wait", { type: "boolean", initializer: "true" }),
|
|
427
|
+
createInlineParameter("annotationText", { type: "string", initializer: '""' })
|
|
428
|
+
],
|
|
407
429
|
(writer) => {
|
|
408
430
|
writer.writeLine(`const candidates = [${candidatesExpr}] as const;`);
|
|
409
431
|
writer.writeLine("let lastError: unknown;");
|
|
@@ -411,7 +433,7 @@ function generateClickMethod(methodName, formattedDataTestId, alternateFormatted
|
|
|
411
433
|
writer.writeLine("const locator = this.locatorByTestId(testId);");
|
|
412
434
|
writer.write("try ").block(() => {
|
|
413
435
|
writer.write("if (await locator.count()) ").block(() => {
|
|
414
|
-
writer.writeLine(
|
|
436
|
+
writer.writeLine("await this.clickLocator(locator, annotationText, wait);");
|
|
415
437
|
writer.writeLine("return;");
|
|
416
438
|
});
|
|
417
439
|
});
|
|
@@ -422,10 +444,10 @@ function generateClickMethod(methodName, formattedDataTestId, alternateFormatted
|
|
|
422
444
|
writer.writeLine(`throw (lastError instanceof Error) ? lastError : new Error("[pom] Failed to click any candidate locator for ${name}.");`);
|
|
423
445
|
}
|
|
424
446
|
);
|
|
425
|
-
const noWaitArgs = argsForForward ? `${argsForForward}, false` : "false";
|
|
447
|
+
const noWaitArgs = argsForForward ? `${argsForForward}, false, annotationText` : "false, annotationText";
|
|
426
448
|
const noWaitMethod = createAsyncMethod(
|
|
427
449
|
noWaitName,
|
|
428
|
-
hasParam(params, "key") ? baseParameters : [],
|
|
450
|
+
hasParam(params, "key") ? [...baseParameters, createInlineParameter("annotationText", { type: "string", initializer: '""' })] : [createInlineParameter("annotationText", { type: "string", initializer: '""' })],
|
|
429
451
|
(writer) => {
|
|
430
452
|
writer.writeLine(`await this.${name}(${noWaitArgs});`);
|
|
431
453
|
}
|
|
@@ -434,21 +456,44 @@ function generateClickMethod(methodName, formattedDataTestId, alternateFormatted
|
|
|
434
456
|
}
|
|
435
457
|
if (hasParam(params, "key")) {
|
|
436
458
|
return [
|
|
437
|
-
createAsyncMethod(
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
459
|
+
createAsyncMethod(
|
|
460
|
+
name,
|
|
461
|
+
[
|
|
462
|
+
...baseParameters,
|
|
463
|
+
createInlineParameter("wait", { type: "boolean", initializer: "true" }),
|
|
464
|
+
createInlineParameter("annotationText", { type: "string", initializer: '""' })
|
|
465
|
+
],
|
|
466
|
+
(writer) => {
|
|
467
|
+
writer.writeLine(`await this.clickByTestId(\`${formattedDataTestId}\`, annotationText, wait);`);
|
|
468
|
+
}
|
|
469
|
+
),
|
|
470
|
+
createAsyncMethod(
|
|
471
|
+
noWaitName,
|
|
472
|
+
[...baseParameters, createInlineParameter("annotationText", { type: "string", initializer: '""' })],
|
|
473
|
+
(writer) => {
|
|
474
|
+
writer.writeLine(`await this.${name}(${argsForForward}, false, annotationText);`);
|
|
475
|
+
}
|
|
476
|
+
)
|
|
443
477
|
];
|
|
444
478
|
}
|
|
445
479
|
return [
|
|
446
|
-
createAsyncMethod(
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
480
|
+
createAsyncMethod(
|
|
481
|
+
name,
|
|
482
|
+
[
|
|
483
|
+
createInlineParameter("wait", { type: "boolean", initializer: "true" }),
|
|
484
|
+
createInlineParameter("annotationText", { type: "string", initializer: '""' })
|
|
485
|
+
],
|
|
486
|
+
(writer) => {
|
|
487
|
+
writer.writeLine(`await this.clickByTestId("${formattedDataTestId}", annotationText, wait);`);
|
|
488
|
+
}
|
|
489
|
+
),
|
|
490
|
+
createAsyncMethod(
|
|
491
|
+
noWaitName,
|
|
492
|
+
[createInlineParameter("annotationText", { type: "string", initializer: '""' })],
|
|
493
|
+
(writer) => {
|
|
494
|
+
writer.writeLine(`await this.${name}(false, annotationText);`);
|
|
495
|
+
}
|
|
496
|
+
)
|
|
452
497
|
];
|
|
453
498
|
}
|
|
454
499
|
function generateRadioMethod(methodName, formattedDataTestId) {
|
|
@@ -2893,10 +2938,13 @@ Fix: make the element identifiable (e.g. add id/name/inner text or use a more sp
|
|
|
2893
2938
|
formattedDataTestId: formattedDataTestIdForPom
|
|
2894
2939
|
},
|
|
2895
2940
|
keyLiteral: rawValue,
|
|
2896
|
-
params: { wait: "boolean = true" }
|
|
2941
|
+
params: { wait: "boolean = true", annotationText: 'string = ""' }
|
|
2897
2942
|
});
|
|
2898
2943
|
if (added) {
|
|
2899
|
-
registerGeneratedMethodSignature(generatedName, {
|
|
2944
|
+
registerGeneratedMethodSignature(generatedName, {
|
|
2945
|
+
params: `wait: boolean = true, annotationText: string = ""`,
|
|
2946
|
+
argNames: ["wait", "annotationText"]
|
|
2947
|
+
});
|
|
2900
2948
|
}
|
|
2901
2949
|
}
|
|
2902
2950
|
return;
|
|
@@ -3157,6 +3205,56 @@ function createRouterIntrospectionVueStubPlugin(options) {
|
|
|
3157
3205
|
}
|
|
3158
3206
|
};
|
|
3159
3207
|
}
|
|
3208
|
+
function snapshotGlobalValue(name) {
|
|
3209
|
+
const g = globalThis;
|
|
3210
|
+
return {
|
|
3211
|
+
descriptor: Object.getOwnPropertyDescriptor(globalThis, name),
|
|
3212
|
+
value: g[name]
|
|
3213
|
+
};
|
|
3214
|
+
}
|
|
3215
|
+
function setTemporaryGlobal(name, value, snapshots) {
|
|
3216
|
+
if (!snapshots.has(name))
|
|
3217
|
+
snapshots.set(name, snapshotGlobalValue(name));
|
|
3218
|
+
const snapshot = snapshots.get(name);
|
|
3219
|
+
if (!snapshot)
|
|
3220
|
+
return false;
|
|
3221
|
+
if (!snapshot.descriptor || snapshot.descriptor.configurable) {
|
|
3222
|
+
Object.defineProperty(globalThis, name, {
|
|
3223
|
+
configurable: true,
|
|
3224
|
+
enumerable: snapshot.descriptor?.enumerable ?? true,
|
|
3225
|
+
writable: true,
|
|
3226
|
+
value
|
|
3227
|
+
});
|
|
3228
|
+
return true;
|
|
3229
|
+
}
|
|
3230
|
+
if ("writable" in snapshot.descriptor && snapshot.descriptor.writable) {
|
|
3231
|
+
Reflect.set(globalThis, name, value);
|
|
3232
|
+
return true;
|
|
3233
|
+
}
|
|
3234
|
+
if (snapshot.descriptor.set) {
|
|
3235
|
+
snapshot.descriptor.set.call(globalThis, value);
|
|
3236
|
+
return true;
|
|
3237
|
+
}
|
|
3238
|
+
return false;
|
|
3239
|
+
}
|
|
3240
|
+
function restoreTemporaryGlobals(snapshots) {
|
|
3241
|
+
for (const [name, snapshot] of Array.from(snapshots.entries()).reverse()) {
|
|
3242
|
+
const { descriptor, value } = snapshot;
|
|
3243
|
+
if (!descriptor) {
|
|
3244
|
+
Reflect.deleteProperty(globalThis, name);
|
|
3245
|
+
continue;
|
|
3246
|
+
}
|
|
3247
|
+
if (descriptor.configurable) {
|
|
3248
|
+
Object.defineProperty(globalThis, name, descriptor);
|
|
3249
|
+
continue;
|
|
3250
|
+
}
|
|
3251
|
+
if ("writable" in descriptor && descriptor.writable) {
|
|
3252
|
+
Reflect.set(globalThis, name, value);
|
|
3253
|
+
continue;
|
|
3254
|
+
}
|
|
3255
|
+
descriptor.set?.call(globalThis, value);
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3160
3258
|
const PARAM_TOKEN_PREFIX = "__VUE_TESTID_PARAM__";
|
|
3161
3259
|
function getParamToken(name) {
|
|
3162
3260
|
return `${PARAM_TOKEN_PREFIX}${name}__`;
|
|
@@ -3505,12 +3603,18 @@ function createMinimalLocation() {
|
|
|
3505
3603
|
ancestorOrigins: { length: 0, contains: () => false, item: () => null, [Symbol.iterator]: [][Symbol.iterator] }
|
|
3506
3604
|
};
|
|
3507
3605
|
}
|
|
3508
|
-
|
|
3606
|
+
function ensureDomShim() {
|
|
3509
3607
|
const g = globalThis;
|
|
3510
3608
|
if (typeof document !== "undefined" && typeof window !== "undefined")
|
|
3511
|
-
return
|
|
3609
|
+
return () => {
|
|
3610
|
+
};
|
|
3512
3611
|
const minimalDoc = createMinimalDocument();
|
|
3513
3612
|
const minimalLocation = createMinimalLocation();
|
|
3613
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
3614
|
+
const setGlobal = (name, value) => {
|
|
3615
|
+
if (!setTemporaryGlobal(name, value, snapshots))
|
|
3616
|
+
debugLog(`could not temporarily install global ${name}`);
|
|
3617
|
+
};
|
|
3514
3618
|
const win = {
|
|
3515
3619
|
document: minimalDoc,
|
|
3516
3620
|
location: minimalLocation,
|
|
@@ -3555,17 +3659,17 @@ async function ensureDomShim() {
|
|
|
3555
3659
|
queueMicrotask,
|
|
3556
3660
|
performance: globalThis.performance
|
|
3557
3661
|
};
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3662
|
+
setGlobal("window", win);
|
|
3663
|
+
setGlobal("document", minimalDoc);
|
|
3664
|
+
setGlobal("location", minimalLocation);
|
|
3561
3665
|
if (!g.self)
|
|
3562
|
-
|
|
3666
|
+
setGlobal("self", win);
|
|
3563
3667
|
if (!g.navigator)
|
|
3564
|
-
|
|
3668
|
+
setGlobal("navigator", win.navigator);
|
|
3565
3669
|
if (!g.history)
|
|
3566
|
-
|
|
3670
|
+
setGlobal("history", win.history);
|
|
3567
3671
|
if (!g.MutationObserver) {
|
|
3568
|
-
|
|
3672
|
+
setGlobal("MutationObserver", class {
|
|
3569
3673
|
disconnect() {
|
|
3570
3674
|
}
|
|
3571
3675
|
observe() {
|
|
@@ -3573,20 +3677,20 @@ async function ensureDomShim() {
|
|
|
3573
3677
|
takeRecords() {
|
|
3574
3678
|
return [];
|
|
3575
3679
|
}
|
|
3576
|
-
};
|
|
3680
|
+
});
|
|
3577
3681
|
}
|
|
3578
3682
|
if (!g.ResizeObserver) {
|
|
3579
|
-
|
|
3683
|
+
setGlobal("ResizeObserver", class {
|
|
3580
3684
|
disconnect() {
|
|
3581
3685
|
}
|
|
3582
3686
|
observe() {
|
|
3583
3687
|
}
|
|
3584
3688
|
unobserve() {
|
|
3585
3689
|
}
|
|
3586
|
-
};
|
|
3690
|
+
});
|
|
3587
3691
|
}
|
|
3588
3692
|
if (!g.IntersectionObserver) {
|
|
3589
|
-
|
|
3693
|
+
setGlobal("IntersectionObserver", class {
|
|
3590
3694
|
disconnect() {
|
|
3591
3695
|
}
|
|
3592
3696
|
observe() {
|
|
@@ -3596,10 +3700,10 @@ async function ensureDomShim() {
|
|
|
3596
3700
|
takeRecords() {
|
|
3597
3701
|
return [];
|
|
3598
3702
|
}
|
|
3599
|
-
};
|
|
3703
|
+
});
|
|
3600
3704
|
}
|
|
3601
3705
|
if (!g.requestIdleCallback) {
|
|
3602
|
-
|
|
3706
|
+
setGlobal("requestIdleCallback", (cb) => setTimeout(() => cb({ didTimeout: false, timeRemaining: () => 0 }), 1));
|
|
3603
3707
|
}
|
|
3604
3708
|
if (!g.localStorage || !g.sessionStorage) {
|
|
3605
3709
|
const storageFactory = () => {
|
|
@@ -3622,12 +3726,15 @@ async function ensureDomShim() {
|
|
|
3622
3726
|
};
|
|
3623
3727
|
};
|
|
3624
3728
|
if (!g.localStorage)
|
|
3625
|
-
|
|
3729
|
+
setGlobal("localStorage", storageFactory());
|
|
3626
3730
|
if (!g.sessionStorage)
|
|
3627
|
-
|
|
3731
|
+
setGlobal("sessionStorage", storageFactory());
|
|
3628
3732
|
}
|
|
3629
3733
|
if (!g.requestAnimationFrame)
|
|
3630
|
-
|
|
3734
|
+
setGlobal("requestAnimationFrame", (cb) => setTimeout(() => cb(Date.now()), 16));
|
|
3735
|
+
return () => {
|
|
3736
|
+
restoreTemporaryGlobals(snapshots);
|
|
3737
|
+
};
|
|
3631
3738
|
}
|
|
3632
3739
|
function unwrapNuxtPageSegment(segment, prefix, suffix) {
|
|
3633
3740
|
if (!segment.startsWith(prefix) || !segment.endsWith(suffix))
|
|
@@ -3745,85 +3852,89 @@ async function parseRouterFileFromCwd(routerEntryPath, options = {}) {
|
|
|
3745
3852
|
}
|
|
3746
3853
|
const cwd = path.dirname(routerEntry);
|
|
3747
3854
|
const moduleShims = normalizeRouterIntrospectionModuleShims(options.moduleShims);
|
|
3748
|
-
|
|
3749
|
-
debugLog(`parseRouterFileFromCwd cwd=${cwd}`);
|
|
3750
|
-
const vite = await import("vite");
|
|
3751
|
-
const server = await vite.createServer({
|
|
3752
|
-
root: cwd,
|
|
3753
|
-
configFile: false,
|
|
3754
|
-
logLevel: "error",
|
|
3755
|
-
// This server is created only to SSR-load the router module. Disable HMR/WebSocket
|
|
3756
|
-
// to avoid port conflicts in dev/test environments.
|
|
3757
|
-
server: { middlewareMode: true, hmr: false, ws: false },
|
|
3758
|
-
appType: "custom",
|
|
3759
|
-
// IMPORTANT:
|
|
3760
|
-
// This internal, short-lived Vite server exists only to `ssrLoadModule()` the router entry.
|
|
3761
|
-
// We close it immediately after reading routes.
|
|
3762
|
-
//
|
|
3763
|
-
// Vite's dependency optimizer (vite:dep-scan / optimizeDeps) runs asynchronously and can
|
|
3764
|
-
// still have pending resolve requests when we call `server.close()`, which surfaces as:
|
|
3765
|
-
// "The server is being restarted or closed. Request is outdated [plugin vite:dep-scan]"
|
|
3766
|
-
//
|
|
3767
|
-
// Disable optimizeDeps entirely for this internal server to avoid that race.
|
|
3768
|
-
optimizeDeps: {
|
|
3769
|
-
disabled: true
|
|
3770
|
-
},
|
|
3771
|
-
resolve: {
|
|
3772
|
-
alias: {
|
|
3773
|
-
"@": cwd
|
|
3774
|
-
}
|
|
3775
|
-
},
|
|
3776
|
-
// Important: Do NOT include @vitejs/plugin-vue here.
|
|
3777
|
-
// We stub all `.vue` imports ourselves, and including the Vue plugin would attempt to parse
|
|
3778
|
-
// those stubbed modules as real SFCs (and fail).
|
|
3779
|
-
plugins: [createRouterIntrospectionVueStubPlugin({ routerEntryAbs: routerEntry, moduleShims })]
|
|
3780
|
-
});
|
|
3855
|
+
const restoreDomShim = ensureDomShim();
|
|
3781
3856
|
try {
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
const
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3857
|
+
debugLog(`parseRouterFileFromCwd cwd=${cwd}`);
|
|
3858
|
+
const vite = await import("vite");
|
|
3859
|
+
const server = await vite.createServer({
|
|
3860
|
+
root: cwd,
|
|
3861
|
+
configFile: false,
|
|
3862
|
+
logLevel: "error",
|
|
3863
|
+
// This server is created only to SSR-load the router module. Disable HMR/WebSocket
|
|
3864
|
+
// to avoid port conflicts in dev/test environments.
|
|
3865
|
+
server: { middlewareMode: true, hmr: false, ws: false },
|
|
3866
|
+
appType: "custom",
|
|
3867
|
+
// IMPORTANT:
|
|
3868
|
+
// This internal, short-lived Vite server exists only to `ssrLoadModule()` the router entry.
|
|
3869
|
+
// We close it immediately after reading routes.
|
|
3870
|
+
//
|
|
3871
|
+
// Vite's dependency optimizer (vite:dep-scan / optimizeDeps) runs asynchronously and can
|
|
3872
|
+
// still have pending resolve requests when we call `server.close()`, which surfaces as:
|
|
3873
|
+
// "The server is being restarted or closed. Request is outdated [plugin vite:dep-scan]"
|
|
3874
|
+
//
|
|
3875
|
+
// Disable optimizeDeps entirely for this internal server to avoid that race.
|
|
3876
|
+
optimizeDeps: {
|
|
3877
|
+
disabled: true
|
|
3878
|
+
},
|
|
3879
|
+
resolve: {
|
|
3880
|
+
alias: {
|
|
3881
|
+
"@": cwd
|
|
3882
|
+
}
|
|
3883
|
+
},
|
|
3884
|
+
// Important: Do NOT include @vitejs/plugin-vue here.
|
|
3885
|
+
// We stub all `.vue` imports ourselves, and including the Vue plugin would attempt to parse
|
|
3886
|
+
// those stubbed modules as real SFCs (and fail).
|
|
3887
|
+
plugins: [createRouterIntrospectionVueStubPlugin({ routerEntryAbs: routerEntry, moduleShims })]
|
|
3888
|
+
});
|
|
3791
3889
|
try {
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
for (const r of router.getRoutes()) {
|
|
3800
|
-
const componentInfo = await getComponentInfoFromRouteRecord(r, { rootDir: cwd });
|
|
3801
|
-
const componentName = resolveIntrospectedComponentName(componentInfo, options.componentNaming);
|
|
3802
|
-
if (!componentName)
|
|
3803
|
-
continue;
|
|
3804
|
-
if (typeof r.path === "string" && r.path.length) {
|
|
3805
|
-
routePathMap.set(r.path, componentName);
|
|
3890
|
+
const moduleId = node_url.pathToFileURL(routerEntry).href;
|
|
3891
|
+
debugLog(`ssrLoadModule(${moduleId}) start`);
|
|
3892
|
+
const mod = await server.ssrLoadModule(moduleId);
|
|
3893
|
+
debugLog(`ssrLoadModule(${moduleId}) done; hasDefault=${typeof mod?.default === "function"}`);
|
|
3894
|
+
const makeRouter = mod?.default;
|
|
3895
|
+
if (typeof makeRouter !== "function") {
|
|
3896
|
+
throw new TypeError(`[vue-pom-generator] ${routerEntry} must export a default router factory function (export default makeRouter).`);
|
|
3806
3897
|
}
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3898
|
+
let router;
|
|
3899
|
+
try {
|
|
3900
|
+
router = makeRouter();
|
|
3901
|
+
} catch (err) {
|
|
3902
|
+
throw new Error(`[vue-pom-generator] makeRouter() invocation failed: ${String(err)}`);
|
|
3810
3903
|
}
|
|
3811
|
-
const
|
|
3812
|
-
const
|
|
3813
|
-
const
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3904
|
+
const routeNameMap = /* @__PURE__ */ new Map();
|
|
3905
|
+
const routePathMap = /* @__PURE__ */ new Map();
|
|
3906
|
+
const routeMetaEntries = [];
|
|
3907
|
+
for (const r of router.getRoutes()) {
|
|
3908
|
+
const componentInfo = await getComponentInfoFromRouteRecord(r, { rootDir: cwd });
|
|
3909
|
+
const componentName = resolveIntrospectedComponentName(componentInfo, options.componentNaming);
|
|
3910
|
+
if (!componentName)
|
|
3911
|
+
continue;
|
|
3912
|
+
if (typeof r.path === "string" && r.path.length) {
|
|
3913
|
+
routePathMap.set(r.path, componentName);
|
|
3914
|
+
}
|
|
3915
|
+
if (typeof r.name === "string" && r.name.length) {
|
|
3916
|
+
const key = toPascalCase(r.name);
|
|
3917
|
+
routeNameMap.set(key, componentName);
|
|
3918
|
+
}
|
|
3919
|
+
const { paramKeys, queryKeys } = getRoutePropsKeys(r);
|
|
3920
|
+
const paramsMeta = getRouteParamMeta(router, r, paramKeys);
|
|
3921
|
+
const pathTemplate = buildRouteTemplate(router, r, paramsMeta.map((p) => p.name));
|
|
3922
|
+
if (typeof pathTemplate === "string" && pathTemplate.length) {
|
|
3923
|
+
routeMetaEntries.push({
|
|
3924
|
+
componentName,
|
|
3925
|
+
pathTemplate,
|
|
3926
|
+
params: paramsMeta,
|
|
3927
|
+
query: queryKeys
|
|
3928
|
+
});
|
|
3929
|
+
}
|
|
3821
3930
|
}
|
|
3931
|
+
return { routeNameMap, routePathMap, routeMetaEntries };
|
|
3932
|
+
} finally {
|
|
3933
|
+
debugLog("closing internal vite server");
|
|
3934
|
+
await server.close();
|
|
3822
3935
|
}
|
|
3823
|
-
return { routeNameMap, routePathMap, routeMetaEntries };
|
|
3824
3936
|
} finally {
|
|
3825
|
-
|
|
3826
|
-
await server.close();
|
|
3937
|
+
restoreDomShim();
|
|
3827
3938
|
}
|
|
3828
3939
|
});
|
|
3829
3940
|
}
|
|
@@ -7997,6 +8108,13 @@ function tryCreateElementMetadata(args) {
|
|
|
7997
8108
|
};
|
|
7998
8109
|
return metadata;
|
|
7999
8110
|
}
|
|
8111
|
+
function resolveCompilerSfcParse(compilerSfc2) {
|
|
8112
|
+
const parse = compilerSfc2.parse ?? compilerSfc2.default?.parse;
|
|
8113
|
+
if (typeof parse !== "function") {
|
|
8114
|
+
throw new TypeError("[vue-pom-generator] Failed to resolve @vue/compiler-sfc.parse.");
|
|
8115
|
+
}
|
|
8116
|
+
return parse;
|
|
8117
|
+
}
|
|
8000
8118
|
function extractMetadataAfterTransform(ast, componentName, elementMetadata, semanticNameMap, testIdAttribute) {
|
|
8001
8119
|
const componentMetadata = /* @__PURE__ */ new Map();
|
|
8002
8120
|
function traverseNode(node) {
|
|
@@ -8193,7 +8311,8 @@ function createVuePluginWithTestIds(options) {
|
|
|
8193
8311
|
}
|
|
8194
8312
|
const componentName = getComponentNameFromPath(cleanPath);
|
|
8195
8313
|
loggerRef.current.debug(`Collecting metadata for ${cleanPath} (component: ${componentName})`);
|
|
8196
|
-
const
|
|
8314
|
+
const compilerSfc2 = await import("@vue/compiler-sfc");
|
|
8315
|
+
const parse = resolveCompilerSfcParse(compilerSfc2);
|
|
8197
8316
|
const compilerDom2 = await import("@vue/compiler-dom");
|
|
8198
8317
|
const compile = compilerDom2.compile;
|
|
8199
8318
|
const { descriptor } = parse(code, { filename: cleanPath });
|