@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/dist/index.mjs CHANGED
@@ -63,6 +63,21 @@ function createLogger(options) {
63
63
  };
64
64
  }
65
65
  const requireFromModule = createRequire(import.meta.url);
66
+ function resolveNuxtKitEntry(cwd) {
67
+ const attemptResolvers = [
68
+ createRequire(path.resolve(cwd, "package.json")),
69
+ requireFromModule
70
+ ];
71
+ let lastError;
72
+ for (const resolver of attemptResolvers) {
73
+ try {
74
+ return resolver.resolve("@nuxt/kit");
75
+ } catch (error) {
76
+ lastError = error instanceof Error ? error : new Error(String(error));
77
+ }
78
+ }
79
+ throw lastError ?? new Error("Unknown module resolution error");
80
+ }
66
81
  function toUniqueResolvedPaths(paths) {
67
82
  return Array.from(new Set(paths.map((value) => path.resolve(value))));
68
83
  }
@@ -173,7 +188,7 @@ async function loadNuxtProjectDiscovery(cwd = process.cwd()) {
173
188
  let loadNuxtConfig;
174
189
  let getLayerDirectories;
175
190
  try {
176
- const nuxtKitEntry = requireFromModule.resolve("@nuxt/kit");
191
+ const nuxtKitEntry = resolveNuxtKitEntry(cwd);
177
192
  ({ loadNuxtConfig, getLayerDirectories } = await import(pathToFileURL(nuxtKitEntry).href));
178
193
  } catch (error) {
179
194
  throw new TypeError(
@@ -362,7 +377,14 @@ function generateClickMethod(methodName, formattedDataTestId, alternateFormatted
362
377
  const candidatesExpr = [formattedDataTestId, ...alternates].map(testIdExpression).join(", ");
363
378
  const clickMethod = createAsyncMethod(
364
379
  name,
365
- hasParam(params, "key") ? [...baseParameters, createInlineParameter("wait", { type: "boolean", initializer: "true" })] : [createInlineParameter("wait", { type: "boolean", initializer: "true" })],
380
+ hasParam(params, "key") ? [
381
+ ...baseParameters,
382
+ createInlineParameter("wait", { type: "boolean", initializer: "true" }),
383
+ createInlineParameter("annotationText", { type: "string", initializer: '""' })
384
+ ] : [
385
+ createInlineParameter("wait", { type: "boolean", initializer: "true" }),
386
+ createInlineParameter("annotationText", { type: "string", initializer: '""' })
387
+ ],
366
388
  (writer) => {
367
389
  writer.writeLine(`const candidates = [${candidatesExpr}] as const;`);
368
390
  writer.writeLine("let lastError: unknown;");
@@ -370,7 +392,7 @@ function generateClickMethod(methodName, formattedDataTestId, alternateFormatted
370
392
  writer.writeLine("const locator = this.locatorByTestId(testId);");
371
393
  writer.write("try ").block(() => {
372
394
  writer.write("if (await locator.count()) ").block(() => {
373
- writer.writeLine('await this.clickLocator(locator, "", wait);');
395
+ writer.writeLine("await this.clickLocator(locator, annotationText, wait);");
374
396
  writer.writeLine("return;");
375
397
  });
376
398
  });
@@ -381,10 +403,10 @@ function generateClickMethod(methodName, formattedDataTestId, alternateFormatted
381
403
  writer.writeLine(`throw (lastError instanceof Error) ? lastError : new Error("[pom] Failed to click any candidate locator for ${name}.");`);
382
404
  }
383
405
  );
384
- const noWaitArgs = argsForForward ? `${argsForForward}, false` : "false";
406
+ const noWaitArgs = argsForForward ? `${argsForForward}, false, annotationText` : "false, annotationText";
385
407
  const noWaitMethod = createAsyncMethod(
386
408
  noWaitName,
387
- hasParam(params, "key") ? baseParameters : [],
409
+ hasParam(params, "key") ? [...baseParameters, createInlineParameter("annotationText", { type: "string", initializer: '""' })] : [createInlineParameter("annotationText", { type: "string", initializer: '""' })],
388
410
  (writer) => {
389
411
  writer.writeLine(`await this.${name}(${noWaitArgs});`);
390
412
  }
@@ -393,21 +415,44 @@ function generateClickMethod(methodName, formattedDataTestId, alternateFormatted
393
415
  }
394
416
  if (hasParam(params, "key")) {
395
417
  return [
396
- createAsyncMethod(name, [...baseParameters, createInlineParameter("wait", { type: "boolean", initializer: "true" })], (writer) => {
397
- writer.writeLine(`await this.clickByTestId(\`${formattedDataTestId}\`, "", wait);`);
398
- }),
399
- createAsyncMethod(noWaitName, baseParameters, (writer) => {
400
- writer.writeLine(`await this.${name}(${argsForForward}, false);`);
401
- })
418
+ createAsyncMethod(
419
+ name,
420
+ [
421
+ ...baseParameters,
422
+ createInlineParameter("wait", { type: "boolean", initializer: "true" }),
423
+ createInlineParameter("annotationText", { type: "string", initializer: '""' })
424
+ ],
425
+ (writer) => {
426
+ writer.writeLine(`await this.clickByTestId(\`${formattedDataTestId}\`, annotationText, wait);`);
427
+ }
428
+ ),
429
+ createAsyncMethod(
430
+ noWaitName,
431
+ [...baseParameters, createInlineParameter("annotationText", { type: "string", initializer: '""' })],
432
+ (writer) => {
433
+ writer.writeLine(`await this.${name}(${argsForForward}, false, annotationText);`);
434
+ }
435
+ )
402
436
  ];
403
437
  }
404
438
  return [
405
- createAsyncMethod(name, [createInlineParameter("wait", { type: "boolean", initializer: "true" })], (writer) => {
406
- writer.writeLine(`await this.clickByTestId("${formattedDataTestId}", "", wait);`);
407
- }),
408
- createAsyncMethod(noWaitName, [], (writer) => {
409
- writer.writeLine(`await this.${name}(false);`);
410
- })
439
+ createAsyncMethod(
440
+ name,
441
+ [
442
+ createInlineParameter("wait", { type: "boolean", initializer: "true" }),
443
+ createInlineParameter("annotationText", { type: "string", initializer: '""' })
444
+ ],
445
+ (writer) => {
446
+ writer.writeLine(`await this.clickByTestId("${formattedDataTestId}", annotationText, wait);`);
447
+ }
448
+ ),
449
+ createAsyncMethod(
450
+ noWaitName,
451
+ [createInlineParameter("annotationText", { type: "string", initializer: '""' })],
452
+ (writer) => {
453
+ writer.writeLine(`await this.${name}(false, annotationText);`);
454
+ }
455
+ )
411
456
  ];
412
457
  }
413
458
  function generateRadioMethod(methodName, formattedDataTestId) {
@@ -2852,10 +2897,13 @@ Fix: make the element identifiable (e.g. add id/name/inner text or use a more sp
2852
2897
  formattedDataTestId: formattedDataTestIdForPom
2853
2898
  },
2854
2899
  keyLiteral: rawValue,
2855
- params: { wait: "boolean = true" }
2900
+ params: { wait: "boolean = true", annotationText: 'string = ""' }
2856
2901
  });
2857
2902
  if (added) {
2858
- registerGeneratedMethodSignature(generatedName, { params: `wait: boolean = true`, argNames: ["wait"] });
2903
+ registerGeneratedMethodSignature(generatedName, {
2904
+ params: `wait: boolean = true, annotationText: string = ""`,
2905
+ argNames: ["wait", "annotationText"]
2906
+ });
2859
2907
  }
2860
2908
  }
2861
2909
  return;
@@ -3116,6 +3164,56 @@ function createRouterIntrospectionVueStubPlugin(options) {
3116
3164
  }
3117
3165
  };
3118
3166
  }
3167
+ function snapshotGlobalValue(name) {
3168
+ const g = globalThis;
3169
+ return {
3170
+ descriptor: Object.getOwnPropertyDescriptor(globalThis, name),
3171
+ value: g[name]
3172
+ };
3173
+ }
3174
+ function setTemporaryGlobal(name, value, snapshots) {
3175
+ if (!snapshots.has(name))
3176
+ snapshots.set(name, snapshotGlobalValue(name));
3177
+ const snapshot = snapshots.get(name);
3178
+ if (!snapshot)
3179
+ return false;
3180
+ if (!snapshot.descriptor || snapshot.descriptor.configurable) {
3181
+ Object.defineProperty(globalThis, name, {
3182
+ configurable: true,
3183
+ enumerable: snapshot.descriptor?.enumerable ?? true,
3184
+ writable: true,
3185
+ value
3186
+ });
3187
+ return true;
3188
+ }
3189
+ if ("writable" in snapshot.descriptor && snapshot.descriptor.writable) {
3190
+ Reflect.set(globalThis, name, value);
3191
+ return true;
3192
+ }
3193
+ if (snapshot.descriptor.set) {
3194
+ snapshot.descriptor.set.call(globalThis, value);
3195
+ return true;
3196
+ }
3197
+ return false;
3198
+ }
3199
+ function restoreTemporaryGlobals(snapshots) {
3200
+ for (const [name, snapshot] of Array.from(snapshots.entries()).reverse()) {
3201
+ const { descriptor, value } = snapshot;
3202
+ if (!descriptor) {
3203
+ Reflect.deleteProperty(globalThis, name);
3204
+ continue;
3205
+ }
3206
+ if (descriptor.configurable) {
3207
+ Object.defineProperty(globalThis, name, descriptor);
3208
+ continue;
3209
+ }
3210
+ if ("writable" in descriptor && descriptor.writable) {
3211
+ Reflect.set(globalThis, name, value);
3212
+ continue;
3213
+ }
3214
+ descriptor.set?.call(globalThis, value);
3215
+ }
3216
+ }
3119
3217
  const PARAM_TOKEN_PREFIX = "__VUE_TESTID_PARAM__";
3120
3218
  function getParamToken(name) {
3121
3219
  return `${PARAM_TOKEN_PREFIX}${name}__`;
@@ -3464,12 +3562,18 @@ function createMinimalLocation() {
3464
3562
  ancestorOrigins: { length: 0, contains: () => false, item: () => null, [Symbol.iterator]: [][Symbol.iterator] }
3465
3563
  };
3466
3564
  }
3467
- async function ensureDomShim() {
3565
+ function ensureDomShim() {
3468
3566
  const g = globalThis;
3469
3567
  if (typeof document !== "undefined" && typeof window !== "undefined")
3470
- return;
3568
+ return () => {
3569
+ };
3471
3570
  const minimalDoc = createMinimalDocument();
3472
3571
  const minimalLocation = createMinimalLocation();
3572
+ const snapshots = /* @__PURE__ */ new Map();
3573
+ const setGlobal = (name, value) => {
3574
+ if (!setTemporaryGlobal(name, value, snapshots))
3575
+ debugLog(`could not temporarily install global ${name}`);
3576
+ };
3473
3577
  const win = {
3474
3578
  document: minimalDoc,
3475
3579
  location: minimalLocation,
@@ -3514,17 +3618,17 @@ async function ensureDomShim() {
3514
3618
  queueMicrotask,
3515
3619
  performance: globalThis.performance
3516
3620
  };
3517
- g.window = win;
3518
- g.document = minimalDoc;
3519
- g.location = minimalLocation;
3621
+ setGlobal("window", win);
3622
+ setGlobal("document", minimalDoc);
3623
+ setGlobal("location", minimalLocation);
3520
3624
  if (!g.self)
3521
- g.self = win;
3625
+ setGlobal("self", win);
3522
3626
  if (!g.navigator)
3523
- g.navigator = win.navigator;
3627
+ setGlobal("navigator", win.navigator);
3524
3628
  if (!g.history)
3525
- g.history = win.history;
3629
+ setGlobal("history", win.history);
3526
3630
  if (!g.MutationObserver) {
3527
- g.MutationObserver = class {
3631
+ setGlobal("MutationObserver", class {
3528
3632
  disconnect() {
3529
3633
  }
3530
3634
  observe() {
@@ -3532,20 +3636,20 @@ async function ensureDomShim() {
3532
3636
  takeRecords() {
3533
3637
  return [];
3534
3638
  }
3535
- };
3639
+ });
3536
3640
  }
3537
3641
  if (!g.ResizeObserver) {
3538
- g.ResizeObserver = class {
3642
+ setGlobal("ResizeObserver", class {
3539
3643
  disconnect() {
3540
3644
  }
3541
3645
  observe() {
3542
3646
  }
3543
3647
  unobserve() {
3544
3648
  }
3545
- };
3649
+ });
3546
3650
  }
3547
3651
  if (!g.IntersectionObserver) {
3548
- g.IntersectionObserver = class {
3652
+ setGlobal("IntersectionObserver", class {
3549
3653
  disconnect() {
3550
3654
  }
3551
3655
  observe() {
@@ -3555,10 +3659,10 @@ async function ensureDomShim() {
3555
3659
  takeRecords() {
3556
3660
  return [];
3557
3661
  }
3558
- };
3662
+ });
3559
3663
  }
3560
3664
  if (!g.requestIdleCallback) {
3561
- g.requestIdleCallback = (cb) => setTimeout(() => cb({ didTimeout: false, timeRemaining: () => 0 }), 1);
3665
+ setGlobal("requestIdleCallback", (cb) => setTimeout(() => cb({ didTimeout: false, timeRemaining: () => 0 }), 1));
3562
3666
  }
3563
3667
  if (!g.localStorage || !g.sessionStorage) {
3564
3668
  const storageFactory = () => {
@@ -3581,12 +3685,15 @@ async function ensureDomShim() {
3581
3685
  };
3582
3686
  };
3583
3687
  if (!g.localStorage)
3584
- g.localStorage = storageFactory();
3688
+ setGlobal("localStorage", storageFactory());
3585
3689
  if (!g.sessionStorage)
3586
- g.sessionStorage = storageFactory();
3690
+ setGlobal("sessionStorage", storageFactory());
3587
3691
  }
3588
3692
  if (!g.requestAnimationFrame)
3589
- g.requestAnimationFrame = (cb) => setTimeout(() => cb(Date.now()), 16);
3693
+ setGlobal("requestAnimationFrame", (cb) => setTimeout(() => cb(Date.now()), 16));
3694
+ return () => {
3695
+ restoreTemporaryGlobals(snapshots);
3696
+ };
3590
3697
  }
3591
3698
  function unwrapNuxtPageSegment(segment, prefix, suffix) {
3592
3699
  if (!segment.startsWith(prefix) || !segment.endsWith(suffix))
@@ -3704,85 +3811,89 @@ async function parseRouterFileFromCwd(routerEntryPath, options = {}) {
3704
3811
  }
3705
3812
  const cwd = path.dirname(routerEntry);
3706
3813
  const moduleShims = normalizeRouterIntrospectionModuleShims(options.moduleShims);
3707
- await ensureDomShim();
3708
- debugLog(`parseRouterFileFromCwd cwd=${cwd}`);
3709
- const vite = await import("vite");
3710
- const server = await vite.createServer({
3711
- root: cwd,
3712
- configFile: false,
3713
- logLevel: "error",
3714
- // This server is created only to SSR-load the router module. Disable HMR/WebSocket
3715
- // to avoid port conflicts in dev/test environments.
3716
- server: { middlewareMode: true, hmr: false, ws: false },
3717
- appType: "custom",
3718
- // IMPORTANT:
3719
- // This internal, short-lived Vite server exists only to `ssrLoadModule()` the router entry.
3720
- // We close it immediately after reading routes.
3721
- //
3722
- // Vite's dependency optimizer (vite:dep-scan / optimizeDeps) runs asynchronously and can
3723
- // still have pending resolve requests when we call `server.close()`, which surfaces as:
3724
- // "The server is being restarted or closed. Request is outdated [plugin vite:dep-scan]"
3725
- //
3726
- // Disable optimizeDeps entirely for this internal server to avoid that race.
3727
- optimizeDeps: {
3728
- disabled: true
3729
- },
3730
- resolve: {
3731
- alias: {
3732
- "@": cwd
3733
- }
3734
- },
3735
- // Important: Do NOT include @vitejs/plugin-vue here.
3736
- // We stub all `.vue` imports ourselves, and including the Vue plugin would attempt to parse
3737
- // those stubbed modules as real SFCs (and fail).
3738
- plugins: [createRouterIntrospectionVueStubPlugin({ routerEntryAbs: routerEntry, moduleShims })]
3739
- });
3814
+ const restoreDomShim = ensureDomShim();
3740
3815
  try {
3741
- const moduleId = pathToFileURL(routerEntry).href;
3742
- debugLog(`ssrLoadModule(${moduleId}) start`);
3743
- const mod = await server.ssrLoadModule(moduleId);
3744
- debugLog(`ssrLoadModule(${moduleId}) done; hasDefault=${typeof mod?.default === "function"}`);
3745
- const makeRouter = mod?.default;
3746
- if (typeof makeRouter !== "function") {
3747
- throw new TypeError(`[vue-pom-generator] ${routerEntry} must export a default router factory function (export default makeRouter).`);
3748
- }
3749
- let router;
3816
+ debugLog(`parseRouterFileFromCwd cwd=${cwd}`);
3817
+ const vite = await import("vite");
3818
+ const server = await vite.createServer({
3819
+ root: cwd,
3820
+ configFile: false,
3821
+ logLevel: "error",
3822
+ // This server is created only to SSR-load the router module. Disable HMR/WebSocket
3823
+ // to avoid port conflicts in dev/test environments.
3824
+ server: { middlewareMode: true, hmr: false, ws: false },
3825
+ appType: "custom",
3826
+ // IMPORTANT:
3827
+ // This internal, short-lived Vite server exists only to `ssrLoadModule()` the router entry.
3828
+ // We close it immediately after reading routes.
3829
+ //
3830
+ // Vite's dependency optimizer (vite:dep-scan / optimizeDeps) runs asynchronously and can
3831
+ // still have pending resolve requests when we call `server.close()`, which surfaces as:
3832
+ // "The server is being restarted or closed. Request is outdated [plugin vite:dep-scan]"
3833
+ //
3834
+ // Disable optimizeDeps entirely for this internal server to avoid that race.
3835
+ optimizeDeps: {
3836
+ disabled: true
3837
+ },
3838
+ resolve: {
3839
+ alias: {
3840
+ "@": cwd
3841
+ }
3842
+ },
3843
+ // Important: Do NOT include @vitejs/plugin-vue here.
3844
+ // We stub all `.vue` imports ourselves, and including the Vue plugin would attempt to parse
3845
+ // those stubbed modules as real SFCs (and fail).
3846
+ plugins: [createRouterIntrospectionVueStubPlugin({ routerEntryAbs: routerEntry, moduleShims })]
3847
+ });
3750
3848
  try {
3751
- router = makeRouter();
3752
- } catch (err) {
3753
- throw new Error(`[vue-pom-generator] makeRouter() invocation failed: ${String(err)}`);
3754
- }
3755
- const routeNameMap = /* @__PURE__ */ new Map();
3756
- const routePathMap = /* @__PURE__ */ new Map();
3757
- const routeMetaEntries = [];
3758
- for (const r of router.getRoutes()) {
3759
- const componentInfo = await getComponentInfoFromRouteRecord(r, { rootDir: cwd });
3760
- const componentName = resolveIntrospectedComponentName(componentInfo, options.componentNaming);
3761
- if (!componentName)
3762
- continue;
3763
- if (typeof r.path === "string" && r.path.length) {
3764
- routePathMap.set(r.path, componentName);
3849
+ const moduleId = pathToFileURL(routerEntry).href;
3850
+ debugLog(`ssrLoadModule(${moduleId}) start`);
3851
+ const mod = await server.ssrLoadModule(moduleId);
3852
+ debugLog(`ssrLoadModule(${moduleId}) done; hasDefault=${typeof mod?.default === "function"}`);
3853
+ const makeRouter = mod?.default;
3854
+ if (typeof makeRouter !== "function") {
3855
+ throw new TypeError(`[vue-pom-generator] ${routerEntry} must export a default router factory function (export default makeRouter).`);
3765
3856
  }
3766
- if (typeof r.name === "string" && r.name.length) {
3767
- const key = toPascalCase(r.name);
3768
- routeNameMap.set(key, componentName);
3857
+ let router;
3858
+ try {
3859
+ router = makeRouter();
3860
+ } catch (err) {
3861
+ throw new Error(`[vue-pom-generator] makeRouter() invocation failed: ${String(err)}`);
3769
3862
  }
3770
- const { paramKeys, queryKeys } = getRoutePropsKeys(r);
3771
- const paramsMeta = getRouteParamMeta(router, r, paramKeys);
3772
- const pathTemplate = buildRouteTemplate(router, r, paramsMeta.map((p) => p.name));
3773
- if (typeof pathTemplate === "string" && pathTemplate.length) {
3774
- routeMetaEntries.push({
3775
- componentName,
3776
- pathTemplate,
3777
- params: paramsMeta,
3778
- query: queryKeys
3779
- });
3863
+ const routeNameMap = /* @__PURE__ */ new Map();
3864
+ const routePathMap = /* @__PURE__ */ new Map();
3865
+ const routeMetaEntries = [];
3866
+ for (const r of router.getRoutes()) {
3867
+ const componentInfo = await getComponentInfoFromRouteRecord(r, { rootDir: cwd });
3868
+ const componentName = resolveIntrospectedComponentName(componentInfo, options.componentNaming);
3869
+ if (!componentName)
3870
+ continue;
3871
+ if (typeof r.path === "string" && r.path.length) {
3872
+ routePathMap.set(r.path, componentName);
3873
+ }
3874
+ if (typeof r.name === "string" && r.name.length) {
3875
+ const key = toPascalCase(r.name);
3876
+ routeNameMap.set(key, componentName);
3877
+ }
3878
+ const { paramKeys, queryKeys } = getRoutePropsKeys(r);
3879
+ const paramsMeta = getRouteParamMeta(router, r, paramKeys);
3880
+ const pathTemplate = buildRouteTemplate(router, r, paramsMeta.map((p) => p.name));
3881
+ if (typeof pathTemplate === "string" && pathTemplate.length) {
3882
+ routeMetaEntries.push({
3883
+ componentName,
3884
+ pathTemplate,
3885
+ params: paramsMeta,
3886
+ query: queryKeys
3887
+ });
3888
+ }
3780
3889
  }
3890
+ return { routeNameMap, routePathMap, routeMetaEntries };
3891
+ } finally {
3892
+ debugLog("closing internal vite server");
3893
+ await server.close();
3781
3894
  }
3782
- return { routeNameMap, routePathMap, routeMetaEntries };
3783
3895
  } finally {
3784
- debugLog("closing internal vite server");
3785
- await server.close();
3896
+ restoreDomShim();
3786
3897
  }
3787
3898
  });
3788
3899
  }
@@ -7956,6 +8067,13 @@ function tryCreateElementMetadata(args) {
7956
8067
  };
7957
8068
  return metadata;
7958
8069
  }
8070
+ function resolveCompilerSfcParse(compilerSfc) {
8071
+ const parse2 = compilerSfc.parse ?? compilerSfc.default?.parse;
8072
+ if (typeof parse2 !== "function") {
8073
+ throw new TypeError("[vue-pom-generator] Failed to resolve @vue/compiler-sfc.parse.");
8074
+ }
8075
+ return parse2;
8076
+ }
7959
8077
  function extractMetadataAfterTransform(ast, componentName, elementMetadata, semanticNameMap, testIdAttribute) {
7960
8078
  const componentMetadata = /* @__PURE__ */ new Map();
7961
8079
  function traverseNode(node) {
@@ -8152,7 +8270,8 @@ function createVuePluginWithTestIds(options) {
8152
8270
  }
8153
8271
  const componentName = getComponentNameFromPath(cleanPath);
8154
8272
  loggerRef.current.debug(`Collecting metadata for ${cleanPath} (component: ${componentName})`);
8155
- const { parse: parse2 } = await import("@vue/compiler-sfc");
8273
+ const compilerSfc = await import("@vue/compiler-sfc");
8274
+ const parse2 = resolveCompilerSfcParse(compilerSfc);
8156
8275
  const compilerDom2 = await import("@vue/compiler-dom");
8157
8276
  const compile = compilerDom2.compile;
8158
8277
  const { descriptor } = parse2(code, { filename: cleanPath });