pomwright 1.3.0 → 1.4.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # pomwright
2
2
 
3
+ ## 1.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#36](https://github.com/DyHex/POMWright/pull/36) [`e307d0e`](https://github.com/DyHex/POMWright/commit/e307d0e871bce4b69f12fa17fa673af3dad8f874) Thanks [@DyHex](https://github.com/DyHex)! - # v1.4.0
8
+
9
+ ## Removed
10
+
11
+ - Dropped deprecated locator schema helpers (legacy numeric indexing and update/updates overloads). Use sub-path keyed indices and `update(subPath, updates)` instead.
12
+
13
+ ## Changed
14
+
15
+ - Simplified nested locator debug logging to count-only checks to avoid CSP-restricted pages failing when `evaluateAll` is blocked.
16
+
3
17
  ## 1.3.0
4
18
 
5
19
  ### Minor Changes
package/dist/index.d.mts CHANGED
@@ -296,7 +296,7 @@ type ExtractSubPaths<Path extends string> = Path extends `${infer Head}.${infer
296
296
  */
297
297
  type SubPaths<LocatorSchemaPathType extends string, LocatorSubstring extends LocatorSchemaPathType | undefined> = LocatorSubstring extends string ? Extract<LocatorSchemaPathType, LocatorSubstring | ExtractSubPaths<LocatorSubstring>> : never;
298
298
  /**
299
- * UpdatableLocatorSchemaProperties represent the properties of LocatorSchema that can be changed by update/updates,
299
+ * UpdatableLocatorSchemaProperties represent the properties of LocatorSchema that can be changed by update,
300
300
  * excluding the locatorSchemaPath itself, which remains immutable.
301
301
  */
302
302
  type LocatorSchemaWithoutPath = Omit<LocatorSchema, "locatorSchemaPath">;
@@ -340,43 +340,11 @@ type LocatorSchemaWithMethods<LocatorSchemaPathType extends string, LocatorSubst
340
340
  *
341
341
  * @example
342
342
  * // Direct usage:
343
- * const submitButton = await poc.getLocatorSchema("main.form.button@submit").update("main.form.button@submit")
343
+ * const submitButton = await poc
344
+ * .getLocatorSchema("main.form.button@submit")
345
+ * .update("main.form.button@submit", { roleOptions: { name: "Submit" } })
344
346
  */
345
347
  update(subPath: SubPaths<LocatorSchemaPathType, LocatorSubstring>, updates: Partial<LocatorSchemaWithoutPath>): LocatorSchemaWithMethods<LocatorSchemaPathType, LocatorSubstring>;
346
- /**
347
- * @deprecated To be removed in version 2.0.0. Use the new `.update(subPath, updates)` method instead, see example.
348
- *
349
- * This deprecated update method takes one argument and only updates the LocatorSchema which the full LocatorSchemaPath resolves to.
350
- *
351
- * @example
352
- * // New update method usage:
353
- * const userInfoSection = await poc
354
- * .getLocatorSchema("main.form.section")
355
- * .update("main.form.section", { locatorOptions: { hasText: "User Info:" } })
356
- * .getNestedLocator();
357
- */
358
- update(updates: Partial<LocatorSchemaWithoutPath>): LocatorSchemaWithMethods<LocatorSchemaPathType, LocatorSubstring>;
359
- /**
360
- * @deprecated To be removed in version 2.0.0. Use the new `.update(subPath, updates)` method instead, chain the
361
- * method for each update if multiple, see example.
362
- *
363
- * This deprecated updates method uses indices to identify which schema to update.
364
- *
365
- * @example
366
- * // New update method usage:
367
- * const userInfoSection = await poc
368
- * .getLocatorSchema("main.form.section")
369
- * .update("main.form", {
370
- * role: "form",
371
- * roleOptions: { name: "Personalia" },
372
- * locatorMethod: GetByMethod.role,
373
- * })
374
- * .update("main.form.section", { locatorOptions: { hasText: /User Info:/i } })
375
- * .getNestedLocator();
376
- */
377
- updates(indexedUpdates: {
378
- [index: number]: Partial<LocatorSchemaWithoutPath> | null;
379
- }): LocatorSchemaWithMethods<LocatorSchemaPathType, LocatorSubstring>;
380
348
  /**
381
349
  * The equivalent of the Playwright locator.filter({...}) method and chainable on .getLocatorSchema(LocatorSchemaPath).
382
350
  * Can be chained multiple times to add multiple filters to the same or different LocatorSchema.
@@ -471,37 +439,6 @@ type LocatorSchemaWithMethods<LocatorSchemaPathType extends string, LocatorSubst
471
439
  getNestedLocator(subPathIndices?: {
472
440
  [K in SubPaths<LocatorSchemaPathType, LocatorSubstring>]?: number | null;
473
441
  }): Promise<Locator>;
474
- /**
475
- * @deprecated To be removed in version 2.0.0. Use getNestedLocator({ LocatorSchemaPath: index }) instead of
476
- * number-based indexing, see example.
477
- *
478
- * @example
479
- * // New usage:
480
- * for (const [index, subscription] of subscriptions.entries()) {
481
- * const inputUsername = await poc
482
- * .getLocatorSchema("main.form.item.input@username")
483
- * .getNestedLocator({ "main.form.item": index });
484
- * await inputUsername.fill(subscription.username);
485
- * await inputUsername.blur();
486
- *
487
- * const enableServiceCheckbox = await poc
488
- * .getLocatorSchema("main.form.item.checkbox@enableService")
489
- * .getNestedLocator({ "main.form.item": index });
490
- * await enableServiceCheckbox.check();
491
- * }
492
- *
493
- * // indexing multiple subPaths:
494
- * const something = await poc
495
- * .getLocatorSchema("main.form.item.something")
496
- * .getNestedLocator({
497
- * "main.form": 0, // locator.first() / locator.nth(0)
498
- * "main.form.item": 1, // locator.nth(1)
499
- * });
500
- * await something.click();
501
- */
502
- getNestedLocator(indices?: {
503
- [key: number]: number | null;
504
- }): Promise<Locator>;
505
442
  /**
506
443
  * This method does not perform nesting,and will return the locator for which the full LocatorSchemaPath resolves to,
507
444
  * provided by getLocatorSchema("...")
@@ -527,7 +464,7 @@ type LocatorSchemaWithMethods<LocatorSchemaPathType extends string, LocatorSubst
527
464
  *
528
465
  * - getLocatorSchema(path):
529
466
  * Returns a deep-copied schema and a chainable object (LocatorSchemaWithMethods) that
530
- * allows calling update, updates, addFilter, and finally getNestedLocator or getLocator.
467
+ * allows calling update, addFilter, and finally getNestedLocator or getLocator.
531
468
  *
532
469
  * - By using WithMethodsClass, we lock LocatorSubstring = P, the chosen path,
533
470
  * ensuring addFilter suggests only valid sub-paths of P.
@@ -566,18 +503,6 @@ declare class GetLocatorBase<LocatorSchemaPathType extends string, LocatorSubstr
566
503
  * Similar to applyUpdate, but we locate the sub-path schema directly by its path.
567
504
  */
568
505
  applyUpdateToSubPath(schemasMap: Map<string, LocatorSchema>, subPath: LocatorSchemaPathType, updates: Partial<LocatorSchemaWithoutPath>): void;
569
- /**
570
- * applyUpdate:
571
- * Applies updates to a single schema within the schemasMap.
572
- */
573
- applyUpdate(schemasMap: Map<string, LocatorSchema>, locatorSchemaPath: LocatorSchemaPathType, updateData: Partial<LocatorSchema>): void;
574
- /**
575
- * applyUpdates:
576
- * Applies multiple updates to multiple schemas in the chain, identified by their path indexes.
577
- */
578
- applyUpdates(schemasMap: Map<string, LocatorSchema>, pathIndexPairs: PathIndexPairs, updatesData: {
579
- [index: number]: Partial<LocatorSchema>;
580
- }): void;
581
506
  /**
582
507
  * createLocatorSchema:
583
508
  * Creates a fresh LocatorSchema object by merging provided schemaDetails with a required locatorSchemaPath.
@@ -597,7 +522,7 @@ declare class GetLocatorBase<LocatorSchemaPathType extends string, LocatorSubstr
597
522
  /**
598
523
  * extractPathsFromSchema:
599
524
  * Splits a path into incremental sub-paths and associates them with optional indices.
600
- * Used by updates and getNestedLocator methods.
525
+ * Used by getNestedLocator methods.
601
526
  */
602
527
  extractPathsFromSchema: (paths: string, indices?: Record<number, number>) => PathIndexPairs;
603
528
  /**
@@ -623,11 +548,6 @@ declare class GetLocatorBase<LocatorSchemaPathType extends string, LocatorSubstr
623
548
  * Helps with logging and debugging complex locator chains.
624
549
  */
625
550
  private evaluateCurrentLocator;
626
- /**
627
- * evaluateAndGetAttributes:
628
- * Extracts tagName and attributes from all elements matched by the locator for debugging purposes.
629
- */
630
- private evaluateAndGetAttributes;
631
551
  }
632
552
 
633
553
  /**
@@ -797,22 +717,6 @@ declare abstract class BasePage<LocatorSchemaPathType extends string, Options ex
797
717
  getNestedLocator<P extends LocatorSchemaPathType>(locatorSchemaPath: P, subPathIndices?: {
798
718
  [K in SubPaths<LocatorSchemaPathType, P>]?: number | null;
799
719
  }): Promise<Locator>;
800
- /**
801
- * @deprecated Use { SubPaths: index } instead of {4:2}, i.e. subPath-based keys instead of indices, see example.
802
- *
803
- * Deprecated short-hand wrapper method for calling .getLocatorSchema(LocatorSchemaPath).getNestedLocator(subPathIndices?)
804
- *
805
- * @example
806
- * // New Usage:
807
- * const something = await poc.getNestedLocator("main.form.item.something", {
808
- * "main.form": 0, // locator.first() / locator.nth(0)
809
- * "main.form.item": 1, // locator.nth(1)
810
- * });
811
- * await something.click();
812
- */
813
- getNestedLocator(locatorSchemaPath: LocatorSchemaPathType, indices?: {
814
- [key: number]: number | null;
815
- } | null): Promise<Locator>;
816
720
  /**
817
721
  * Short-hand wrapper method for calling .getLocatorSchema(LocatorSchemaPath).getLocator()
818
722
  *
package/dist/index.d.ts CHANGED
@@ -296,7 +296,7 @@ type ExtractSubPaths<Path extends string> = Path extends `${infer Head}.${infer
296
296
  */
297
297
  type SubPaths<LocatorSchemaPathType extends string, LocatorSubstring extends LocatorSchemaPathType | undefined> = LocatorSubstring extends string ? Extract<LocatorSchemaPathType, LocatorSubstring | ExtractSubPaths<LocatorSubstring>> : never;
298
298
  /**
299
- * UpdatableLocatorSchemaProperties represent the properties of LocatorSchema that can be changed by update/updates,
299
+ * UpdatableLocatorSchemaProperties represent the properties of LocatorSchema that can be changed by update,
300
300
  * excluding the locatorSchemaPath itself, which remains immutable.
301
301
  */
302
302
  type LocatorSchemaWithoutPath = Omit<LocatorSchema, "locatorSchemaPath">;
@@ -340,43 +340,11 @@ type LocatorSchemaWithMethods<LocatorSchemaPathType extends string, LocatorSubst
340
340
  *
341
341
  * @example
342
342
  * // Direct usage:
343
- * const submitButton = await poc.getLocatorSchema("main.form.button@submit").update("main.form.button@submit")
343
+ * const submitButton = await poc
344
+ * .getLocatorSchema("main.form.button@submit")
345
+ * .update("main.form.button@submit", { roleOptions: { name: "Submit" } })
344
346
  */
345
347
  update(subPath: SubPaths<LocatorSchemaPathType, LocatorSubstring>, updates: Partial<LocatorSchemaWithoutPath>): LocatorSchemaWithMethods<LocatorSchemaPathType, LocatorSubstring>;
346
- /**
347
- * @deprecated To be removed in version 2.0.0. Use the new `.update(subPath, updates)` method instead, see example.
348
- *
349
- * This deprecated update method takes one argument and only updates the LocatorSchema which the full LocatorSchemaPath resolves to.
350
- *
351
- * @example
352
- * // New update method usage:
353
- * const userInfoSection = await poc
354
- * .getLocatorSchema("main.form.section")
355
- * .update("main.form.section", { locatorOptions: { hasText: "User Info:" } })
356
- * .getNestedLocator();
357
- */
358
- update(updates: Partial<LocatorSchemaWithoutPath>): LocatorSchemaWithMethods<LocatorSchemaPathType, LocatorSubstring>;
359
- /**
360
- * @deprecated To be removed in version 2.0.0. Use the new `.update(subPath, updates)` method instead, chain the
361
- * method for each update if multiple, see example.
362
- *
363
- * This deprecated updates method uses indices to identify which schema to update.
364
- *
365
- * @example
366
- * // New update method usage:
367
- * const userInfoSection = await poc
368
- * .getLocatorSchema("main.form.section")
369
- * .update("main.form", {
370
- * role: "form",
371
- * roleOptions: { name: "Personalia" },
372
- * locatorMethod: GetByMethod.role,
373
- * })
374
- * .update("main.form.section", { locatorOptions: { hasText: /User Info:/i } })
375
- * .getNestedLocator();
376
- */
377
- updates(indexedUpdates: {
378
- [index: number]: Partial<LocatorSchemaWithoutPath> | null;
379
- }): LocatorSchemaWithMethods<LocatorSchemaPathType, LocatorSubstring>;
380
348
  /**
381
349
  * The equivalent of the Playwright locator.filter({...}) method and chainable on .getLocatorSchema(LocatorSchemaPath).
382
350
  * Can be chained multiple times to add multiple filters to the same or different LocatorSchema.
@@ -471,37 +439,6 @@ type LocatorSchemaWithMethods<LocatorSchemaPathType extends string, LocatorSubst
471
439
  getNestedLocator(subPathIndices?: {
472
440
  [K in SubPaths<LocatorSchemaPathType, LocatorSubstring>]?: number | null;
473
441
  }): Promise<Locator>;
474
- /**
475
- * @deprecated To be removed in version 2.0.0. Use getNestedLocator({ LocatorSchemaPath: index }) instead of
476
- * number-based indexing, see example.
477
- *
478
- * @example
479
- * // New usage:
480
- * for (const [index, subscription] of subscriptions.entries()) {
481
- * const inputUsername = await poc
482
- * .getLocatorSchema("main.form.item.input@username")
483
- * .getNestedLocator({ "main.form.item": index });
484
- * await inputUsername.fill(subscription.username);
485
- * await inputUsername.blur();
486
- *
487
- * const enableServiceCheckbox = await poc
488
- * .getLocatorSchema("main.form.item.checkbox@enableService")
489
- * .getNestedLocator({ "main.form.item": index });
490
- * await enableServiceCheckbox.check();
491
- * }
492
- *
493
- * // indexing multiple subPaths:
494
- * const something = await poc
495
- * .getLocatorSchema("main.form.item.something")
496
- * .getNestedLocator({
497
- * "main.form": 0, // locator.first() / locator.nth(0)
498
- * "main.form.item": 1, // locator.nth(1)
499
- * });
500
- * await something.click();
501
- */
502
- getNestedLocator(indices?: {
503
- [key: number]: number | null;
504
- }): Promise<Locator>;
505
442
  /**
506
443
  * This method does not perform nesting,and will return the locator for which the full LocatorSchemaPath resolves to,
507
444
  * provided by getLocatorSchema("...")
@@ -527,7 +464,7 @@ type LocatorSchemaWithMethods<LocatorSchemaPathType extends string, LocatorSubst
527
464
  *
528
465
  * - getLocatorSchema(path):
529
466
  * Returns a deep-copied schema and a chainable object (LocatorSchemaWithMethods) that
530
- * allows calling update, updates, addFilter, and finally getNestedLocator or getLocator.
467
+ * allows calling update, addFilter, and finally getNestedLocator or getLocator.
531
468
  *
532
469
  * - By using WithMethodsClass, we lock LocatorSubstring = P, the chosen path,
533
470
  * ensuring addFilter suggests only valid sub-paths of P.
@@ -566,18 +503,6 @@ declare class GetLocatorBase<LocatorSchemaPathType extends string, LocatorSubstr
566
503
  * Similar to applyUpdate, but we locate the sub-path schema directly by its path.
567
504
  */
568
505
  applyUpdateToSubPath(schemasMap: Map<string, LocatorSchema>, subPath: LocatorSchemaPathType, updates: Partial<LocatorSchemaWithoutPath>): void;
569
- /**
570
- * applyUpdate:
571
- * Applies updates to a single schema within the schemasMap.
572
- */
573
- applyUpdate(schemasMap: Map<string, LocatorSchema>, locatorSchemaPath: LocatorSchemaPathType, updateData: Partial<LocatorSchema>): void;
574
- /**
575
- * applyUpdates:
576
- * Applies multiple updates to multiple schemas in the chain, identified by their path indexes.
577
- */
578
- applyUpdates(schemasMap: Map<string, LocatorSchema>, pathIndexPairs: PathIndexPairs, updatesData: {
579
- [index: number]: Partial<LocatorSchema>;
580
- }): void;
581
506
  /**
582
507
  * createLocatorSchema:
583
508
  * Creates a fresh LocatorSchema object by merging provided schemaDetails with a required locatorSchemaPath.
@@ -597,7 +522,7 @@ declare class GetLocatorBase<LocatorSchemaPathType extends string, LocatorSubstr
597
522
  /**
598
523
  * extractPathsFromSchema:
599
524
  * Splits a path into incremental sub-paths and associates them with optional indices.
600
- * Used by updates and getNestedLocator methods.
525
+ * Used by getNestedLocator methods.
601
526
  */
602
527
  extractPathsFromSchema: (paths: string, indices?: Record<number, number>) => PathIndexPairs;
603
528
  /**
@@ -623,11 +548,6 @@ declare class GetLocatorBase<LocatorSchemaPathType extends string, LocatorSubstr
623
548
  * Helps with logging and debugging complex locator chains.
624
549
  */
625
550
  private evaluateCurrentLocator;
626
- /**
627
- * evaluateAndGetAttributes:
628
- * Extracts tagName and attributes from all elements matched by the locator for debugging purposes.
629
- */
630
- private evaluateAndGetAttributes;
631
551
  }
632
552
 
633
553
  /**
@@ -797,22 +717,6 @@ declare abstract class BasePage<LocatorSchemaPathType extends string, Options ex
797
717
  getNestedLocator<P extends LocatorSchemaPathType>(locatorSchemaPath: P, subPathIndices?: {
798
718
  [K in SubPaths<LocatorSchemaPathType, P>]?: number | null;
799
719
  }): Promise<Locator>;
800
- /**
801
- * @deprecated Use { SubPaths: index } instead of {4:2}, i.e. subPath-based keys instead of indices, see example.
802
- *
803
- * Deprecated short-hand wrapper method for calling .getLocatorSchema(LocatorSchemaPath).getNestedLocator(subPathIndices?)
804
- *
805
- * @example
806
- * // New Usage:
807
- * const something = await poc.getNestedLocator("main.form.item.something", {
808
- * "main.form": 0, // locator.first() / locator.nth(0)
809
- * "main.form.item": 1, // locator.nth(1)
810
- * });
811
- * await something.click();
812
- */
813
- getNestedLocator(locatorSchemaPath: LocatorSchemaPathType, indices?: {
814
- [key: number]: number | null;
815
- } | null): Promise<Locator>;
816
720
  /**
817
721
  * Short-hand wrapper method for calling .getLocatorSchema(LocatorSchemaPath).getLocator()
818
722
  *
package/dist/index.js CHANGED
@@ -271,7 +271,6 @@ var GetBy = class {
271
271
  // src/helpers/getLocatorBase.ts
272
272
  var REQUIRED_PROPERTIES_FOR_LOCATOR_SCHEMA_WITH_METHODS = [
273
273
  "update",
274
- "updates",
275
274
  "addFilter",
276
275
  "getNestedLocator",
277
276
  "getLocator",
@@ -378,41 +377,6 @@ var GetLocatorBase = class {
378
377
  schemasMap.set(subPath, updatedSchema);
379
378
  }
380
379
  }
381
- /**
382
- * applyUpdate:
383
- * Applies updates to a single schema within the schemasMap.
384
- */
385
- applyUpdate(schemasMap, locatorSchemaPath, updateData) {
386
- const schema = schemasMap.get(locatorSchemaPath);
387
- if (schema) {
388
- const updatedSchema = this.deepMerge(schema, updateData);
389
- if (this.isLocatorSchemaWithMethods(schema)) {
390
- Object.assign(schema, updatedSchema);
391
- } else {
392
- throw new Error("Invalid LocatorSchema object provided for update method.");
393
- }
394
- }
395
- }
396
- /**
397
- * applyUpdates:
398
- * Applies multiple updates to multiple schemas in the chain, identified by their path indexes.
399
- */
400
- applyUpdates(schemasMap, pathIndexPairs, updatesData) {
401
- for (const [index, updateAtIndex] of Object.entries(updatesData)) {
402
- const path = pathIndexPairs[Number.parseInt(index)]?.path;
403
- if (path && updateAtIndex) {
404
- const schema = schemasMap.get(path);
405
- if (schema) {
406
- const updatedSchema = this.deepMerge(schema, updateAtIndex);
407
- if (this.isLocatorSchemaWithMethods(schema)) {
408
- Object.assign(schema, updatedSchema);
409
- } else {
410
- schemasMap.set(path, updatedSchema);
411
- }
412
- }
413
- }
414
- }
415
- }
416
380
  /**
417
381
  * createLocatorSchema:
418
382
  * Creates a fresh LocatorSchema object by merging provided schemaDetails with a required locatorSchemaPath.
@@ -454,7 +418,7 @@ Attempted to Add Schema: ${JSON.stringify(newLocatorSchema, null, 2)}`
454
418
  /**
455
419
  * extractPathsFromSchema:
456
420
  * Splits a path into incremental sub-paths and associates them with optional indices.
457
- * Used by updates and getNestedLocator methods.
421
+ * Used by getNestedLocator methods.
458
422
  */
459
423
  extractPathsFromSchema = (paths, indices = {}) => {
460
424
  const schemaParts = paths.split(".");
@@ -636,27 +600,14 @@ Attempted to Add Schema: ${JSON.stringify(newLocatorSchema, null, 2)}`
636
600
  Note: "iFrame locators evaluation not implemented"
637
601
  });
638
602
  } else {
639
- const elementsData = await this.evaluateAndGetAttributes(currentLocator);
603
+ const elementCount = await currentLocator.count();
640
604
  resultsArray.push({
641
605
  currentLocatorString: `${currentLocator}`,
642
- resolved: elementsData.length > 0,
643
- elementCount: elementsData.length,
644
- elementsResolvedTo: elementsData
606
+ resolved: elementCount > 0,
607
+ elementCount
645
608
  });
646
609
  }
647
610
  };
648
- /**
649
- * evaluateAndGetAttributes:
650
- * Extracts tagName and attributes from all elements matched by the locator for debugging purposes.
651
- */
652
- evaluateAndGetAttributes = async (pwLocator) => {
653
- return await pwLocator.evaluateAll(
654
- (objects) => objects.map((el) => {
655
- const elementAttributes = el.hasAttributes() ? Object.fromEntries(Array.from(el.attributes).map(({ name, value }) => [name, value])) : {};
656
- return { tagName: el.tagName, attributes: elementAttributes };
657
- })
658
- );
659
- };
660
611
  };
661
612
  var WithMethodsClass = class extends GetLocatorBase {
662
613
  constructor(pageObjectClass, log, locatorSubstring, schemasMap) {
@@ -668,30 +619,18 @@ var WithMethodsClass = class extends GetLocatorBase {
668
619
  locatorSchemaPath;
669
620
  /**
670
621
  * init:
671
- * Assigns the locatorSchemaPath and binds methods (update, updates, addFilter, getNestedLocator, getLocator)
622
+ * Assigns the locatorSchemaPath and binds methods (update, addFilter, getNestedLocator, getLocator)
672
623
  * directly on the locatorSchemaCopy. Returns the modified copy, now fully chainable and type-safe.
673
624
  */
674
625
  init(locatorSchemaPath, locatorSchemaCopy) {
675
626
  this.locatorSchemaPath = locatorSchemaPath;
676
627
  const self = this;
677
- locatorSchemaCopy.update = function(a, b) {
628
+ locatorSchemaCopy.update = function(subPath, updates) {
678
629
  const fullPath = this.locatorSchemaPath;
679
- if (b === void 0) {
680
- const updates = a;
681
- self.applyUpdate(self.schemasMap, self.locatorSchemaPath, updates);
682
- } else {
683
- const subPath = a;
684
- const updates = b;
685
- if (!(subPath === fullPath || fullPath.startsWith(`${subPath}.`))) {
686
- throw new Error(`Invalid sub-path: '${subPath}' is not a valid sub-path of '${fullPath}'.`);
687
- }
688
- self.applyUpdateToSubPath(self.schemasMap, subPath, updates);
630
+ if (!(subPath === fullPath || fullPath.startsWith(`${subPath}.`))) {
631
+ throw new Error(`Invalid sub-path: '${subPath}' is not a valid sub-path of '${fullPath}'.`);
689
632
  }
690
- return this;
691
- };
692
- locatorSchemaCopy.updates = function(indexedUpdates) {
693
- const pathIndexPairs = self.extractPathsFromSchema(self.locatorSchemaPath);
694
- self.applyUpdates(self.schemasMap, pathIndexPairs, indexedUpdates);
633
+ self.applyUpdateToSubPath(self.schemasMap, subPath, updates);
695
634
  return this;
696
635
  };
697
636
  locatorSchemaCopy.addFilter = function(subPath, filterData) {
@@ -723,46 +662,33 @@ ${allowedPaths.join(",\n")}`
723
662
  {}
724
663
  );
725
664
  }
726
- const keys = Object.keys(arg);
727
- const isNumberKey = keys.every((key) => /^\d+$/.test(key));
728
665
  const numericIndices = {};
729
- if (isNumberKey) {
730
- for (const [key, value] of Object.entries(arg)) {
731
- const index = Number(key);
732
- if (typeof value === "number" && value >= 0) {
733
- numericIndices[index] = value;
734
- } else if (value !== null) {
735
- throw new Error(`Invalid index value at key '${key}': Expected a positive number or null.`);
736
- }
737
- }
738
- } else {
739
- const pathIndexPairs = self.extractPathsFromSchema(self.locatorSchemaPath);
740
- const pathToIndexMap = new Map(pathIndexPairs.map((pair, idx) => [pair.path, idx]));
741
- for (const [subPath, value] of Object.entries(arg)) {
742
- if (!self.schemasMap.has(subPath)) {
743
- const validPaths = Array.from(self.schemasMap.keys());
744
- throw new Error(
745
- `Invalid sub-path '${subPath}' in getNestedLocator. Allowed sub-paths are:
666
+ const pathIndexPairs = self.extractPathsFromSchema(self.locatorSchemaPath);
667
+ const pathToIndexMap = new Map(pathIndexPairs.map((pair, idx) => [pair.path, idx]));
668
+ for (const [subPath, value] of Object.entries(arg)) {
669
+ if (!self.schemasMap.has(subPath)) {
670
+ const validPaths = Array.from(self.schemasMap.keys());
671
+ throw new Error(
672
+ `Invalid sub-path '${subPath}' in getNestedLocator. Allowed sub-paths are:
746
673
  ${validPaths.join(",\n")}`
747
- );
748
- }
749
- if (!pathToIndexMap.has(subPath)) {
750
- const validPaths = pathIndexPairs.map((p) => p.path).filter((path) => self.schemasMap.has(path));
751
- throw new Error(
752
- `Invalid sub-path '${subPath}' in getNestedLocator. Allowed sub-paths are:
674
+ );
675
+ }
676
+ if (!pathToIndexMap.has(subPath)) {
677
+ const validPaths = pathIndexPairs.map((p) => p.path).filter((path) => self.schemasMap.has(path));
678
+ throw new Error(
679
+ `Invalid sub-path '${subPath}' in getNestedLocator. Allowed sub-paths are:
753
680
  ${validPaths.join(",\n")}`
754
- );
755
- }
756
- const numericIndex = pathToIndexMap.get(subPath);
757
- if (numericIndex === void 0) {
758
- throw new Error(`Sub-path '${subPath}' not found in pathToIndexMap.`);
759
- }
760
- if (value !== null && (typeof value !== "number" || value < 0)) {
761
- throw new Error(`Invalid index for sub-path '${subPath}': Expected a positive number or null.`);
762
- }
763
- if (value !== null) {
764
- numericIndices[numericIndex] = value;
765
- }
681
+ );
682
+ }
683
+ const numericIndex = pathToIndexMap.get(subPath);
684
+ if (numericIndex === void 0) {
685
+ throw new Error(`Sub-path '${subPath}' not found in pathToIndexMap.`);
686
+ }
687
+ if (value !== null && (typeof value !== "number" || value < 0)) {
688
+ throw new Error(`Invalid index for sub-path '${subPath}': Expected a positive number or null.`);
689
+ }
690
+ if (value !== null) {
691
+ numericIndices[numericIndex] = value;
766
692
  }
767
693
  }
768
694
  return await self.buildNestedLocator(
package/dist/index.mjs CHANGED
@@ -240,7 +240,6 @@ var GetBy = class {
240
240
  // src/helpers/getLocatorBase.ts
241
241
  var REQUIRED_PROPERTIES_FOR_LOCATOR_SCHEMA_WITH_METHODS = [
242
242
  "update",
243
- "updates",
244
243
  "addFilter",
245
244
  "getNestedLocator",
246
245
  "getLocator",
@@ -347,41 +346,6 @@ var GetLocatorBase = class {
347
346
  schemasMap.set(subPath, updatedSchema);
348
347
  }
349
348
  }
350
- /**
351
- * applyUpdate:
352
- * Applies updates to a single schema within the schemasMap.
353
- */
354
- applyUpdate(schemasMap, locatorSchemaPath, updateData) {
355
- const schema = schemasMap.get(locatorSchemaPath);
356
- if (schema) {
357
- const updatedSchema = this.deepMerge(schema, updateData);
358
- if (this.isLocatorSchemaWithMethods(schema)) {
359
- Object.assign(schema, updatedSchema);
360
- } else {
361
- throw new Error("Invalid LocatorSchema object provided for update method.");
362
- }
363
- }
364
- }
365
- /**
366
- * applyUpdates:
367
- * Applies multiple updates to multiple schemas in the chain, identified by their path indexes.
368
- */
369
- applyUpdates(schemasMap, pathIndexPairs, updatesData) {
370
- for (const [index, updateAtIndex] of Object.entries(updatesData)) {
371
- const path = pathIndexPairs[Number.parseInt(index)]?.path;
372
- if (path && updateAtIndex) {
373
- const schema = schemasMap.get(path);
374
- if (schema) {
375
- const updatedSchema = this.deepMerge(schema, updateAtIndex);
376
- if (this.isLocatorSchemaWithMethods(schema)) {
377
- Object.assign(schema, updatedSchema);
378
- } else {
379
- schemasMap.set(path, updatedSchema);
380
- }
381
- }
382
- }
383
- }
384
- }
385
349
  /**
386
350
  * createLocatorSchema:
387
351
  * Creates a fresh LocatorSchema object by merging provided schemaDetails with a required locatorSchemaPath.
@@ -423,7 +387,7 @@ Attempted to Add Schema: ${JSON.stringify(newLocatorSchema, null, 2)}`
423
387
  /**
424
388
  * extractPathsFromSchema:
425
389
  * Splits a path into incremental sub-paths and associates them with optional indices.
426
- * Used by updates and getNestedLocator methods.
390
+ * Used by getNestedLocator methods.
427
391
  */
428
392
  extractPathsFromSchema = (paths, indices = {}) => {
429
393
  const schemaParts = paths.split(".");
@@ -605,27 +569,14 @@ Attempted to Add Schema: ${JSON.stringify(newLocatorSchema, null, 2)}`
605
569
  Note: "iFrame locators evaluation not implemented"
606
570
  });
607
571
  } else {
608
- const elementsData = await this.evaluateAndGetAttributes(currentLocator);
572
+ const elementCount = await currentLocator.count();
609
573
  resultsArray.push({
610
574
  currentLocatorString: `${currentLocator}`,
611
- resolved: elementsData.length > 0,
612
- elementCount: elementsData.length,
613
- elementsResolvedTo: elementsData
575
+ resolved: elementCount > 0,
576
+ elementCount
614
577
  });
615
578
  }
616
579
  };
617
- /**
618
- * evaluateAndGetAttributes:
619
- * Extracts tagName and attributes from all elements matched by the locator for debugging purposes.
620
- */
621
- evaluateAndGetAttributes = async (pwLocator) => {
622
- return await pwLocator.evaluateAll(
623
- (objects) => objects.map((el) => {
624
- const elementAttributes = el.hasAttributes() ? Object.fromEntries(Array.from(el.attributes).map(({ name, value }) => [name, value])) : {};
625
- return { tagName: el.tagName, attributes: elementAttributes };
626
- })
627
- );
628
- };
629
580
  };
630
581
  var WithMethodsClass = class extends GetLocatorBase {
631
582
  constructor(pageObjectClass, log, locatorSubstring, schemasMap) {
@@ -637,30 +588,18 @@ var WithMethodsClass = class extends GetLocatorBase {
637
588
  locatorSchemaPath;
638
589
  /**
639
590
  * init:
640
- * Assigns the locatorSchemaPath and binds methods (update, updates, addFilter, getNestedLocator, getLocator)
591
+ * Assigns the locatorSchemaPath and binds methods (update, addFilter, getNestedLocator, getLocator)
641
592
  * directly on the locatorSchemaCopy. Returns the modified copy, now fully chainable and type-safe.
642
593
  */
643
594
  init(locatorSchemaPath, locatorSchemaCopy) {
644
595
  this.locatorSchemaPath = locatorSchemaPath;
645
596
  const self = this;
646
- locatorSchemaCopy.update = function(a, b) {
597
+ locatorSchemaCopy.update = function(subPath, updates) {
647
598
  const fullPath = this.locatorSchemaPath;
648
- if (b === void 0) {
649
- const updates = a;
650
- self.applyUpdate(self.schemasMap, self.locatorSchemaPath, updates);
651
- } else {
652
- const subPath = a;
653
- const updates = b;
654
- if (!(subPath === fullPath || fullPath.startsWith(`${subPath}.`))) {
655
- throw new Error(`Invalid sub-path: '${subPath}' is not a valid sub-path of '${fullPath}'.`);
656
- }
657
- self.applyUpdateToSubPath(self.schemasMap, subPath, updates);
599
+ if (!(subPath === fullPath || fullPath.startsWith(`${subPath}.`))) {
600
+ throw new Error(`Invalid sub-path: '${subPath}' is not a valid sub-path of '${fullPath}'.`);
658
601
  }
659
- return this;
660
- };
661
- locatorSchemaCopy.updates = function(indexedUpdates) {
662
- const pathIndexPairs = self.extractPathsFromSchema(self.locatorSchemaPath);
663
- self.applyUpdates(self.schemasMap, pathIndexPairs, indexedUpdates);
602
+ self.applyUpdateToSubPath(self.schemasMap, subPath, updates);
664
603
  return this;
665
604
  };
666
605
  locatorSchemaCopy.addFilter = function(subPath, filterData) {
@@ -692,46 +631,33 @@ ${allowedPaths.join(",\n")}`
692
631
  {}
693
632
  );
694
633
  }
695
- const keys = Object.keys(arg);
696
- const isNumberKey = keys.every((key) => /^\d+$/.test(key));
697
634
  const numericIndices = {};
698
- if (isNumberKey) {
699
- for (const [key, value] of Object.entries(arg)) {
700
- const index = Number(key);
701
- if (typeof value === "number" && value >= 0) {
702
- numericIndices[index] = value;
703
- } else if (value !== null) {
704
- throw new Error(`Invalid index value at key '${key}': Expected a positive number or null.`);
705
- }
706
- }
707
- } else {
708
- const pathIndexPairs = self.extractPathsFromSchema(self.locatorSchemaPath);
709
- const pathToIndexMap = new Map(pathIndexPairs.map((pair, idx) => [pair.path, idx]));
710
- for (const [subPath, value] of Object.entries(arg)) {
711
- if (!self.schemasMap.has(subPath)) {
712
- const validPaths = Array.from(self.schemasMap.keys());
713
- throw new Error(
714
- `Invalid sub-path '${subPath}' in getNestedLocator. Allowed sub-paths are:
635
+ const pathIndexPairs = self.extractPathsFromSchema(self.locatorSchemaPath);
636
+ const pathToIndexMap = new Map(pathIndexPairs.map((pair, idx) => [pair.path, idx]));
637
+ for (const [subPath, value] of Object.entries(arg)) {
638
+ if (!self.schemasMap.has(subPath)) {
639
+ const validPaths = Array.from(self.schemasMap.keys());
640
+ throw new Error(
641
+ `Invalid sub-path '${subPath}' in getNestedLocator. Allowed sub-paths are:
715
642
  ${validPaths.join(",\n")}`
716
- );
717
- }
718
- if (!pathToIndexMap.has(subPath)) {
719
- const validPaths = pathIndexPairs.map((p) => p.path).filter((path) => self.schemasMap.has(path));
720
- throw new Error(
721
- `Invalid sub-path '${subPath}' in getNestedLocator. Allowed sub-paths are:
643
+ );
644
+ }
645
+ if (!pathToIndexMap.has(subPath)) {
646
+ const validPaths = pathIndexPairs.map((p) => p.path).filter((path) => self.schemasMap.has(path));
647
+ throw new Error(
648
+ `Invalid sub-path '${subPath}' in getNestedLocator. Allowed sub-paths are:
722
649
  ${validPaths.join(",\n")}`
723
- );
724
- }
725
- const numericIndex = pathToIndexMap.get(subPath);
726
- if (numericIndex === void 0) {
727
- throw new Error(`Sub-path '${subPath}' not found in pathToIndexMap.`);
728
- }
729
- if (value !== null && (typeof value !== "number" || value < 0)) {
730
- throw new Error(`Invalid index for sub-path '${subPath}': Expected a positive number or null.`);
731
- }
732
- if (value !== null) {
733
- numericIndices[numericIndex] = value;
734
- }
650
+ );
651
+ }
652
+ const numericIndex = pathToIndexMap.get(subPath);
653
+ if (numericIndex === void 0) {
654
+ throw new Error(`Sub-path '${subPath}' not found in pathToIndexMap.`);
655
+ }
656
+ if (value !== null && (typeof value !== "number" || value < 0)) {
657
+ throw new Error(`Invalid index for sub-path '${subPath}': Expected a positive number or null.`);
658
+ }
659
+ if (value !== null) {
660
+ numericIndices[numericIndex] = value;
735
661
  }
736
662
  }
737
663
  return await self.buildNestedLocator(
@@ -137,8 +137,6 @@ test("specify index for nested locators", async ({ profile }) => {
137
137
  });
138
138
  ```
139
139
 
140
- > Legacy numeric indices are still supported but will be removed in a future major version. Prefer keyed sub paths as shown above.
141
-
142
140
  ## Building chains with `getLocatorSchema()`
143
141
 
144
142
  `getLocatorSchema(path)` returns a deep copy of every schema that makes up the `path` plus chainable helpers for refining the locator. All manipulations happen on the copy, so the original definitions inside the page object stay immutable.
@@ -249,18 +247,4 @@ await editButtonUpdated.click();
249
247
  // returns a fresh deep copy of the original schema chain.
250
248
  ```
251
249
 
252
- ## Migrating from deprecated helpers
253
-
254
- Earlier versions exposed index-based helpers. They continue to work but are deprecated in favour of the sub-path syntax described above.
255
-
256
- ```ts
257
- // old
258
- await profile.getNestedLocator("content.region.details.button.save", { 4: 2 });
259
-
260
- // new
261
- await profile.getNestedLocator("content.region.details.button.save", {
262
- "content.region.details.button.save": 2
263
- });
264
- ```
265
-
266
250
  Switching to sub-path keys makes updates easier when `LocatorSchemaPath` strings change, and TypeScript will warn you if you mistype a path. While improving readability.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pomwright",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "POMWright is a complementary test framework for Playwright written in TypeScript.",
5
5
  "repository": {
6
6
  "type": "git",