pw-core 1.2.0 → 1.2.1

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.
Files changed (86) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +777 -0
  4. package/dist/codegen/config/context-weights.d.ts +8 -0
  5. package/dist/codegen/config/context-weights.js +11 -0
  6. package/dist/codegen/config/ignored-attributes.d.ts +1 -0
  7. package/dist/codegen/config/ignored-attributes.js +4 -0
  8. package/dist/codegen/config/ignored-classes.d.ts +1 -0
  9. package/dist/codegen/config/ignored-classes.js +144 -0
  10. package/dist/codegen/config/ignored-values.d.ts +1 -0
  11. package/dist/codegen/config/ignored-values.js +4 -0
  12. package/dist/codegen/config/index.d.ts +29 -0
  13. package/dist/codegen/config/index.js +17 -0
  14. package/dist/codegen/config/strategy-order.d.ts +1 -0
  15. package/dist/codegen/config/strategy-order.js +18 -0
  16. package/dist/codegen/config/weights.d.ts +15 -0
  17. package/dist/codegen/config/weights.js +18 -0
  18. package/dist/codegen/floating-panel/client.d.ts +1 -0
  19. package/dist/codegen/floating-panel/client.js +248 -0
  20. package/dist/codegen/floating-panel/index.d.ts +4 -0
  21. package/dist/codegen/floating-panel/index.js +20 -0
  22. package/dist/codegen/floating-panel/manager.d.ts +19 -0
  23. package/dist/codegen/floating-panel/manager.js +90 -0
  24. package/dist/codegen/floating-panel/template.d.ts +2 -0
  25. package/dist/codegen/floating-panel/template.js +58 -0
  26. package/dist/codegen/floating-panel/types.d.ts +7 -0
  27. package/dist/codegen/floating-panel/types.js +2 -0
  28. package/dist/codegen/generator/action.validator.d.ts +5 -0
  29. package/dist/codegen/generator/action.validator.js +27 -0
  30. package/dist/codegen/generator/index.d.ts +13 -0
  31. package/dist/codegen/generator/index.js +724 -0
  32. package/dist/codegen/generator/locator.restricted.d.ts +36 -0
  33. package/dist/codegen/generator/locator.restricted.js +127 -0
  34. package/dist/codegen/generator/locator.validator.d.ts +8 -0
  35. package/dist/codegen/generator/locator.validator.js +38 -0
  36. package/dist/codegen/hover-tracker/client.d.ts +1 -0
  37. package/dist/codegen/hover-tracker/client.js +75 -0
  38. package/dist/codegen/hover-tracker/index.d.ts +3 -0
  39. package/dist/codegen/hover-tracker/index.js +19 -0
  40. package/dist/codegen/hover-tracker/manager.d.ts +11 -0
  41. package/dist/codegen/hover-tracker/manager.js +28 -0
  42. package/dist/codegen/hover-tracker/types.d.ts +3 -0
  43. package/dist/codegen/hover-tracker/types.js +2 -0
  44. package/dist/codegen/index.d.ts +35 -0
  45. package/dist/codegen/index.js +1147 -0
  46. package/dist/codegen/key-utils.d.ts +23 -0
  47. package/dist/codegen/key-utils.js +68 -0
  48. package/dist/codegen/scorer/base-score.d.ts +1 -0
  49. package/dist/codegen/scorer/base-score.js +7 -0
  50. package/dist/codegen/scorer/context-score.d.ts +2 -0
  51. package/dist/codegen/scorer/context-score.js +27 -0
  52. package/dist/codegen/scorer/index.d.ts +5 -0
  53. package/dist/codegen/scorer/index.js +23 -0
  54. package/dist/codegen/scorer/locator.ranking.d.ts +15 -0
  55. package/dist/codegen/scorer/locator.ranking.js +83 -0
  56. package/dist/codegen/scorer/semantic-score.d.ts +1 -0
  57. package/dist/codegen/scorer/semantic-score.js +47 -0
  58. package/dist/codegen/types.d.ts +35 -0
  59. package/dist/codegen/types.js +2 -0
  60. package/dist/component/table.js +14 -10
  61. package/dist/constants/methods.d.ts +2 -0
  62. package/dist/constants/methods.js +33 -0
  63. package/dist/constants/strategies.d.ts +2 -0
  64. package/dist/constants/strategies.js +47 -0
  65. package/dist/page/actions/locator-actions.js +15 -4
  66. package/dist/page/assertions/verify-chain.d.ts +39 -32
  67. package/dist/page/assertions/verify-chain.js +18 -4
  68. package/dist/page/assertions/verify-helpers.js +12 -3
  69. package/dist/page/config.d.ts +109 -71
  70. package/dist/page/config.js +10 -31
  71. package/dist/page/locators/dynamic-locator-resolver.js +29 -9
  72. package/dist/page/locators/resolver.d.ts +15 -15
  73. package/dist/page/locators/resolver.js +151 -32
  74. package/dist/page/registry.d.ts +43 -6
  75. package/dist/page/registry.js +90 -18
  76. package/dist/page/typed-page.d.ts +33 -29
  77. package/dist/page/typed-page.js +40 -11
  78. package/dist/page/types/proxy-methods.d.ts +69 -54
  79. package/dist/page/types/validation.d.ts +48 -1
  80. package/dist/page/utils/caller-location.js +13 -9
  81. package/dist/page/utils/formatter.js +6 -3
  82. package/dist/types/methods.d.ts +4 -0
  83. package/dist/types/methods.js +2 -0
  84. package/dist/types/strategies.d.ts +17 -0
  85. package/dist/types/strategies.js +2 -0
  86. package/package.json +8 -1
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Key creation utilities for codegen-generated registry keys.
3
+ *
4
+ * Rules:
5
+ * - Custom keys (testId, selector) are always camelCase
6
+ * - No spaces, hyphens, or special characters
7
+ * - Leading digits are trimmed
8
+ * - Trailing digits are preserved (they may be disambiguation suffixes)
9
+ * - Role suffixes (Btn, Input) are appended after sanitization
10
+ */
11
+ /**
12
+ * Convert an arbitrary string into a clean camelCase registry key.
13
+ *
14
+ * @example
15
+ * toRegistryKey('GET api/app/projects List all projects') => 'getApiAppProjectsListAllProjects'
16
+ * toRegistryKey('01Dynamic-Locators') => 'dynamicLocators'
17
+ * toRegistryKey('POST api/app/projects Create-a-project') => 'postApiAppProjectsCreateAProject'
18
+ * toRegistryKey('switch-to-k6-core') => 'switchToK6Core'
19
+ * toRegistryKey('hello world') => 'helloWorld'
20
+ */
21
+ export declare function toRegistryKey(str: string, options?: {
22
+ roleSuffix?: string;
23
+ }): string;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /**
3
+ * Key creation utilities for codegen-generated registry keys.
4
+ *
5
+ * Rules:
6
+ * - Custom keys (testId, selector) are always camelCase
7
+ * - No spaces, hyphens, or special characters
8
+ * - Leading digits are trimmed
9
+ * - Trailing digits are preserved (they may be disambiguation suffixes)
10
+ * - Role suffixes (Btn, Input) are appended after sanitization
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.toRegistryKey = toRegistryKey;
14
+ /**
15
+ * Convert an arbitrary string into a clean camelCase registry key.
16
+ *
17
+ * @example
18
+ * toRegistryKey('GET api/app/projects List all projects') => 'getApiAppProjectsListAllProjects'
19
+ * toRegistryKey('01Dynamic-Locators') => 'dynamicLocators'
20
+ * toRegistryKey('POST api/app/projects Create-a-project') => 'postApiAppProjectsCreateAProject'
21
+ * toRegistryKey('switch-to-k6-core') => 'switchToK6Core'
22
+ * toRegistryKey('hello world') => 'helloWorld'
23
+ */
24
+ function toRegistryKey(str, options) {
25
+ if (!str)
26
+ return 'element';
27
+ // Strip all non-alphanumeric characters except spaces (used as word separators)
28
+ // First, normalize common separators (hyphens, underscores, slashes, dots) to spaces
29
+ let normalized = str
30
+ .replace(/[-_/\\.]+/g, ' ')
31
+ // Remove any remaining special characters (keep letters, digits, spaces)
32
+ .replace(/[^a-zA-Z0-9\s]/g, '')
33
+ .trim();
34
+ if (!normalized)
35
+ return 'element';
36
+ // Split into words on whitespace and camelCase boundaries
37
+ const words = normalized
38
+ .replace(/([a-z])([A-Z])/g, '$1 $2') // split camelCase
39
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2') // split consecutive uppercase
40
+ .split(/\s+/)
41
+ .filter(Boolean);
42
+ if (words.length === 0)
43
+ return 'element';
44
+ // Build camelCase
45
+ const camel = words
46
+ .map((word, idx) => {
47
+ if (idx === 0)
48
+ return word.toLowerCase();
49
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
50
+ })
51
+ .join('');
52
+ // Trim leading digits
53
+ let result = camel.replace(/^\d+/, '');
54
+ if (!result)
55
+ return 'element';
56
+ // Append role suffix if requested (e.g. 'Btn' for buttons)
57
+ if (options?.roleSuffix) {
58
+ const lowerResult = result.toLowerCase();
59
+ const lowerSuffix = options.roleSuffix.toLowerCase();
60
+ if (!lowerResult.endsWith(lowerSuffix)) {
61
+ result += options.roleSuffix;
62
+ }
63
+ }
64
+ // Hard cap at 40 characters
65
+ if (result.length > 40)
66
+ result = result.slice(0, 40);
67
+ return result;
68
+ }
@@ -0,0 +1 @@
1
+ export declare function getBaseScore(strategyName: string): number;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getBaseScore = getBaseScore;
4
+ const config_1 = require("../config");
5
+ function getBaseScore(strategyName) {
6
+ return config_1.codegenConfig.weights[strategyName] ?? 0;
7
+ }
@@ -0,0 +1,2 @@
1
+ import { DOMContext } from '../types';
2
+ export declare function getContextScore(context: DOMContext): number;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getContextScore = getContextScore;
4
+ const config_1 = require("../config");
5
+ function getContextScore(context) {
6
+ let score = 0;
7
+ const cw = config_1.codegenConfig.contextWeights;
8
+ if (context.accessibleName) {
9
+ score += cw.accessibleName || 0;
10
+ }
11
+ if (context.siblingText) {
12
+ score += cw.siblingText || 0;
13
+ }
14
+ if (context.parentText) {
15
+ score += cw.parentText || 0;
16
+ }
17
+ if (context.nearbyHeading) {
18
+ score += cw.heading || 0;
19
+ }
20
+ if (context.parentAttributes) {
21
+ const hasSemanticParent = Object.keys(context.parentAttributes).some((attr) => attr.startsWith('data-') || attr === 'id' || attr === 'role');
22
+ if (hasSemanticParent) {
23
+ score += cw.semanticParent || 0;
24
+ }
25
+ }
26
+ return score;
27
+ }
@@ -0,0 +1,5 @@
1
+ export * from './base-score';
2
+ export { getBaseScore as getStrategyScore } from './base-score';
3
+ export * from './semantic-score';
4
+ export * from './context-score';
5
+ export * from './locator.ranking';
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.getStrategyScore = void 0;
18
+ __exportStar(require("./base-score"), exports);
19
+ var base_score_1 = require("./base-score");
20
+ Object.defineProperty(exports, "getStrategyScore", { enumerable: true, get: function () { return base_score_1.getBaseScore; } });
21
+ __exportStar(require("./semantic-score"), exports);
22
+ __exportStar(require("./context-score"), exports);
23
+ __exportStar(require("./locator.ranking"), exports);
@@ -0,0 +1,15 @@
1
+ export interface RankingRule {
2
+ strategy: string;
3
+ source?: 'target' | 'child' | 'sibling' | 'parent' | 'ancestor';
4
+ attrName?: string | RegExp;
5
+ roleVal?: string;
6
+ score: number;
7
+ }
8
+ export declare const priorityRankingRules: RankingRule[];
9
+ export declare function getPriorityScore(c: {
10
+ strategy: string;
11
+ source: string;
12
+ depth: number;
13
+ attrName?: string;
14
+ roleVal?: string;
15
+ }): number;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.priorityRankingRules = void 0;
4
+ exports.getPriorityScore = getPriorityScore;
5
+ exports.priorityRankingRules = [
6
+ { strategy: 'testId', source: 'target', score: 1000 },
7
+ { strategy: 'testId', source: 'sibling', score: 980 },
8
+ { strategy: 'testId', source: 'parent', score: 970 },
9
+ { strategy: 'testId', source: 'ancestor', score: 960 },
10
+ { strategy: 'dataAttribute', attrName: /data-test-id|data-testid|datatestid/i, source: 'target', score: 980 },
11
+ { strategy: 'dataAttribute', attrName: /data-test-id|data-testid|datatestid/i, source: 'sibling', score: 960 },
12
+ { strategy: 'dataAttribute', attrName: /data-test-id|data-testid|datatestid/i, source: 'parent', score: 950 },
13
+ { strategy: 'dataAttribute', attrName: /data-test-id|data-testid|datatestid/i, source: 'ancestor', score: 940 },
14
+ { strategy: 'id', source: 'target', score: 960 },
15
+ { strategy: 'id', source: 'sibling', score: 940 },
16
+ { strategy: 'id', source: 'parent', score: 930 },
17
+ { strategy: 'id', source: 'ancestor', score: 920 },
18
+ { strategy: 'dataAttribute', attrName: 'data-parent-id', source: 'target', score: 940 },
19
+ { strategy: 'dataAttribute', attrName: 'data-parent-id', source: 'sibling', score: 925 },
20
+ { strategy: 'dataAttribute', attrName: 'data-parent-id', source: 'parent', score: 915 },
21
+ { strategy: 'dataAttribute', attrName: 'data-parent-id', source: 'ancestor', score: 905 },
22
+ { strategy: 'dataAttribute', attrName: /data-.*id$/i, source: 'target', score: 920 },
23
+ { strategy: 'dataAttribute', attrName: /data-.*id$/i, source: 'sibling', score: 875 },
24
+ { strategy: 'dataAttribute', attrName: /data-.*id$/i, source: 'parent', score: 825 },
25
+ { strategy: 'dataAttribute', attrName: /data-.*id$/i, source: 'ancestor', score: 775 },
26
+ { strategy: 'dataAttribute', attrName: /id/i, source: 'target', score: 900 },
27
+ { strategy: 'dataAttribute', attrName: /id/i, source: 'sibling', score: 860 },
28
+ { strategy: 'dataAttribute', attrName: /id/i, source: 'parent', score: 810 },
29
+ { strategy: 'dataAttribute', attrName: /id/i, source: 'ancestor', score: 760 },
30
+ { strategy: 'role', roleVal: 'link', source: 'target', score: 880 },
31
+ { strategy: 'role', roleVal: 'link', source: 'sibling', score: 840 },
32
+ { strategy: 'role', roleVal: 'link', source: 'parent', score: 790 },
33
+ { strategy: 'role', roleVal: 'link', source: 'ancestor', score: 740 },
34
+ { strategy: 'role', roleVal: 'button', source: 'target', score: 870 },
35
+ { strategy: 'role', roleVal: 'button', source: 'sibling', score: 830 },
36
+ { strategy: 'role', roleVal: 'button', source: 'parent', score: 780 },
37
+ { strategy: 'role', roleVal: 'button', source: 'ancestor', score: 730 },
38
+ { strategy: 'text', source: 'target', score: 550 },
39
+ { strategy: 'text', source: 'sibling', score: 500 },
40
+ { strategy: 'text', source: 'parent', score: 450 },
41
+ { strategy: 'text', source: 'ancestor', score: 400 },
42
+ { strategy: 'role', source: 'target', score: 750 },
43
+ { strategy: 'role', source: 'sibling', score: 710 },
44
+ { strategy: 'role', source: 'parent', score: 660 },
45
+ { strategy: 'role', source: 'ancestor', score: 610 },
46
+ { strategy: 'dataAttribute', attrName: 'data-section', score: 625 },
47
+ { strategy: 'dataAttribute', attrName: 'data-page', score: 620 },
48
+ { strategy: 'dataAttribute', attrName: 'data-component', score: 615 },
49
+ { strategy: 'dataAttribute', score: 600 },
50
+ { strategy: 'label', attrName: 'aria-labelledby', score: 575 },
51
+ { strategy: 'label', attrName: 'title', score: 550 },
52
+ { strategy: 'label', score: 570 },
53
+ { strategy: 'placeholder', score: 565 },
54
+ { strategy: 'altText', score: 563 },
55
+ { strategy: 'title', score: 562 },
56
+ { strategy: 'class', score: 500 },
57
+ { strategy: 'css', score: 400 },
58
+ { strategy: 'xpath', score: 300 }
59
+ ];
60
+ function getPriorityScore(c) {
61
+ const isIdAttr = c.attrName && /id/i.test(c.attrName);
62
+ for (const rule of exports.priorityRankingRules) {
63
+ if (rule.strategy !== c.strategy)
64
+ continue;
65
+ if (rule.source && rule.source !== c.source)
66
+ continue;
67
+ if (rule.roleVal && rule.roleVal !== c.roleVal)
68
+ continue;
69
+ if (rule.attrName) {
70
+ if (typeof rule.attrName === 'string') {
71
+ if (rule.attrName !== c.attrName)
72
+ continue;
73
+ }
74
+ else {
75
+ const nameToTest = isIdAttr ? 'id' : (c.attrName || '');
76
+ if (!rule.attrName.test(nameToTest))
77
+ continue;
78
+ }
79
+ }
80
+ return rule.score;
81
+ }
82
+ return 100; // default CSS
83
+ }
@@ -0,0 +1 @@
1
+ export declare function getSemanticScore(value: string | null): number;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSemanticScore = getSemanticScore;
4
+ function getSemanticScore(value) {
5
+ if (!value)
6
+ return 0;
7
+ let score = 0;
8
+ // Hyphenated values are intentional naming (e.g. "why-pw-core", "page-registry")
9
+ if (value.includes('-'))
10
+ score += 10;
11
+ // Longer values are more descriptive
12
+ if (value.length > 5)
13
+ score += 5;
14
+ if (value.length > 10)
15
+ score += 5;
16
+ // Exclude purely numeric or long random sequences
17
+ if (!/\d{4,}/.test(value))
18
+ score += 10;
19
+ // Pure words (no digits) are more semantic
20
+ if (/^[a-zA-Z-_]+$/.test(value))
21
+ score += 5;
22
+ // Penalize extremely short generic values
23
+ if (value.length <= 3)
24
+ score -= 15;
25
+ // Penalize single-word utility-like values (e.g. "flex", "block", "hidden")
26
+ const utilityNames = [
27
+ 'flex', 'grid', 'block', 'inline', 'hidden', 'visible', 'relative', 'absolute',
28
+ 'fixed', 'sticky', 'static', 'auto', 'none', 'inherit', 'initial', 'unset',
29
+ 'revert', 'polyline', 'svg', 'path', 'circle', 'rect', 'div', 'span', 'section',
30
+ 'article', 'main', 'header', 'footer', 'nav', 'aside', 'tbody', 'thead', 'tr',
31
+ 'td', 'th'
32
+ ];
33
+ if (utilityNames.includes(value.toLowerCase()))
34
+ score -= 30;
35
+ // Penalize CSS utility-pattern values (e.g. transition-all, border-0, shadow-lg)
36
+ const utilityPatterns = [
37
+ /^transition-/, /^transform-/, /^duration-/, /^ease-/, /^delay-/, /^animate-/,
38
+ /^shadow-/, /^opacity-/, /^blur-/, /^scale-/, /^translate-/, /^rotate-/,
39
+ /^skew-/, /^origin-/, /^border-/, /^rounded-/, /^ring-/, /^outline-/, /^bg-/,
40
+ /^text-/, /^font-/, /^leading-/, /^tracking-/, /^w-/, /^h-/, /^min-/, /^max-/,
41
+ /^gap-/, /^space-/, /^m[tblrxy]?-/, /^p[tblrxy]?-/, /^col-/, /^row-/, /^grid-/,
42
+ /^flex-/, /^z-/, /^inset-/, /^top-/, /^right-/, /^bottom-/, /^left-/
43
+ ];
44
+ if (utilityPatterns.some((p) => p.test(value)))
45
+ score -= 25;
46
+ return score;
47
+ }
@@ -0,0 +1,35 @@
1
+ export interface DOMContext {
2
+ parentText?: string;
3
+ siblingText?: string;
4
+ nearbyHeading?: string;
5
+ accessibleName?: string;
6
+ parentAttributes?: Record<string, string>;
7
+ siblingAttributes?: Record<string, string>;
8
+ }
9
+ export interface Candidate {
10
+ selector: string;
11
+ source: 'target' | 'child' | 'sibling' | 'parent' | 'ancestor';
12
+ strategy: string;
13
+ depth: number;
14
+ baseScore: number;
15
+ semanticScore: number;
16
+ proximityScore: number;
17
+ similarityScore: number;
18
+ uniquenessScore: number;
19
+ totalScore: number;
20
+ unique: boolean;
21
+ valueToScore?: string;
22
+ }
23
+ export interface LocatorCandidate extends Candidate {
24
+ locator: string;
25
+ contextScore: number;
26
+ nearbyText?: string;
27
+ parentText?: string;
28
+ accessibleName?: string;
29
+ generatedKey?: string;
30
+ }
31
+ export interface LocatorStrategy {
32
+ name: string;
33
+ matches(element: Element): boolean;
34
+ build(element: Element): LocatorCandidate | null;
35
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -20,15 +20,15 @@ class TableRows extends Array {
20
20
  return this[0] ? this[0][key] : undefined;
21
21
  }
22
22
  // Return the first matching row
23
- return this.find(row => row[key] === value);
23
+ return this.find((row) => row[key] === value);
24
24
  }
25
25
  getAll(key, value) {
26
26
  if (arguments.length === 1) {
27
27
  // Return the values of the key from all rows
28
- return this.map(row => row[key]);
28
+ return this.map((row) => row[key]);
29
29
  }
30
30
  // Return all matching rows
31
- return this.filter(row => row[key] === value);
31
+ return this.filter((row) => row[key] === value);
32
32
  }
33
33
  }
34
34
  exports.TableRows = TableRows;
@@ -42,7 +42,9 @@ class Table {
42
42
  */
43
43
  async getHeaders() {
44
44
  return test_1.test.step(`Get headers of table`, async () => {
45
- const headers = await this.root.locator('th').evaluateAll(ths => ths.map(th => th.textContent?.trim().toLowerCase() || ''));
45
+ const headers = await this.root
46
+ .locator('th')
47
+ .evaluateAll((ths) => ths.map((th) => th.textContent?.trim().toLowerCase() || ''));
46
48
  return headers;
47
49
  }, { box: true, location: (0, caller_location_1.getCallerLocation)() });
48
50
  }
@@ -53,9 +55,11 @@ class Table {
53
55
  async getRows() {
54
56
  return test_1.test.step('Get table rows', async () => {
55
57
  const headers = await this.getHeaders();
56
- const rowsData = await this.root.locator('tbody tr, tr[data-testid="transaction-row"]').evaluateAll((trs, headers) => {
57
- return trs.map(tr => {
58
- const cells = Array.from(tr.querySelectorAll('td')).map(td => td.textContent?.trim() || '');
58
+ const rowsData = await this.root
59
+ .locator('tbody tr, tr[data-testid="transaction-row"]')
60
+ .evaluateAll((trs, headers) => {
61
+ return trs.map((tr) => {
62
+ const cells = Array.from(tr.querySelectorAll('td')).map((td) => td.textContent?.trim() || '');
59
63
  if (cells.length === 0)
60
64
  return null; // Skip header or empty rows
61
65
  const rowData = {};
@@ -83,8 +87,8 @@ class Table {
83
87
  */
84
88
  async getRowCount() {
85
89
  return test_1.test.step('Get table row count', async () => {
86
- return await this.root.locator('tbody tr, tr[data-testid="transaction-row"]').evaluateAll(trs => {
87
- return trs.filter(tr => tr.querySelectorAll('td').length > 0).length;
90
+ return await this.root.locator('tbody tr, tr[data-testid="transaction-row"]').evaluateAll((trs) => {
91
+ return trs.filter((tr) => tr.querySelectorAll('td').length > 0).length;
88
92
  });
89
93
  }, { box: true, location: (0, caller_location_1.getCallerLocation)() });
90
94
  }
@@ -100,7 +104,7 @@ class Table {
100
104
  }
101
105
  return await this.root.evaluate((tableEl, { rowIndex, columnIndex }) => {
102
106
  const trs = Array.from(tableEl.querySelectorAll('tbody tr, tr[data-testid="transaction-row"]'));
103
- const dataRows = trs.filter(tr => tr.querySelectorAll('td').length > 0);
107
+ const dataRows = trs.filter((tr) => tr.querySelectorAll('td').length > 0);
104
108
  if (rowIndex < 0 || rowIndex >= dataRows.length) {
105
109
  throw new Error(`Row index ${rowIndex} is out of bounds (0 to ${dataRows.length - 1})`);
106
110
  }
@@ -0,0 +1,2 @@
1
+ export declare const zeroArgMethodsList: readonly ["click", "dblclick", "hover", "focus", "blur", "check", "uncheck", "clear", "waitFor", "isChecked", "isDisabled", "isVisible", "textContent", "innerText", "allInnerTexts", "allTextContents", "count", "scrollIntoViewIfNeeded", "boundingBox"];
2
+ export declare const oneArgMethodsList: readonly ["fill", "press", "pressSequentially", "selectOption", "setInputFiles", "getAttribute", "dragTo"];
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.oneArgMethodsList = exports.zeroArgMethodsList = void 0;
4
+ exports.zeroArgMethodsList = [
5
+ 'click',
6
+ 'dblclick',
7
+ 'hover',
8
+ 'focus',
9
+ 'blur',
10
+ 'check',
11
+ 'uncheck',
12
+ 'clear',
13
+ 'waitFor',
14
+ 'isChecked',
15
+ 'isDisabled',
16
+ 'isVisible',
17
+ 'textContent',
18
+ 'innerText',
19
+ 'allInnerTexts',
20
+ 'allTextContents',
21
+ 'count',
22
+ 'scrollIntoViewIfNeeded',
23
+ 'boundingBox'
24
+ ];
25
+ exports.oneArgMethodsList = [
26
+ 'fill',
27
+ 'press',
28
+ 'pressSequentially',
29
+ 'selectOption',
30
+ 'setInputFiles',
31
+ 'getAttribute',
32
+ 'dragTo'
33
+ ];
@@ -0,0 +1,2 @@
1
+ export declare const rolesList: readonly ["button", "checkbox", "radio", "heading", "link", "dialog", "list", "listbox", "textbox", "menu", "menuitem", "option", "row", "cell", "tab", "tabpanel", "grid", "gridcell", "combobox", "switch", "progressbar", "status", "tooltip", "tree", "treeitem", "article", "banner", "navigation", "main", "form", "region", "searchbox"];
2
+ export declare const strategyList: readonly ["testId", "selector", "text", "label", "title", "placeholder", "altText", "button", "checkbox", "radio", "heading", "link", "dialog", "list", "listbox", "textbox", "menu", "menuitem", "option", "row", "cell", "tab", "tabpanel", "grid", "gridcell", "combobox", "switch", "progressbar", "status", "tooltip", "tree", "treeitem", "article", "banner", "navigation", "main", "form", "region", "searchbox"];
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.strategyList = exports.rolesList = void 0;
4
+ exports.rolesList = [
5
+ 'button',
6
+ 'checkbox',
7
+ 'radio',
8
+ 'heading',
9
+ 'link',
10
+ 'dialog',
11
+ 'list',
12
+ 'listbox',
13
+ 'textbox',
14
+ 'menu',
15
+ 'menuitem',
16
+ 'option',
17
+ 'row',
18
+ 'cell',
19
+ 'tab',
20
+ 'tabpanel',
21
+ 'grid',
22
+ 'gridcell',
23
+ 'combobox',
24
+ 'switch',
25
+ 'progressbar',
26
+ 'status',
27
+ 'tooltip',
28
+ 'tree',
29
+ 'treeitem',
30
+ 'article',
31
+ 'banner',
32
+ 'navigation',
33
+ 'main',
34
+ 'form',
35
+ 'region',
36
+ 'searchbox'
37
+ ];
38
+ exports.strategyList = [
39
+ 'testId',
40
+ 'selector',
41
+ 'text',
42
+ 'label',
43
+ 'title',
44
+ 'placeholder',
45
+ 'altText',
46
+ ...exports.rolesList
47
+ ];
@@ -23,7 +23,13 @@ function executeAction(prop, resolveLocatorFn, timeout, args) {
23
23
  }
24
24
  }
25
25
  const isCount = prop === 'count';
26
- const locator = resolveLocatorFn(locatorKey, { nth: optNth, hasText: optHasText, raw: isCount });
26
+ const userOptions = optionsIndex !== -1 && methodArgs.length > optionsIndex ? methodArgs[optionsIndex] : undefined;
27
+ const locator = resolveLocatorFn(locatorKey, {
28
+ nth: optNth,
29
+ hasText: optHasText,
30
+ raw: isCount,
31
+ ...userOptions
32
+ });
27
33
  const method = locator[prop];
28
34
  if (typeof method !== 'function') {
29
35
  throw new Error(`Property '${prop}' does not exist on Locator.`);
@@ -31,6 +37,13 @@ function executeAction(prop, resolveLocatorFn, timeout, args) {
31
37
  if (prop === 'dragTo' && methodArgs.length > 0) {
32
38
  methodArgs[0] = resolveLocatorFn(methodArgs[0]);
33
39
  }
40
+ if (optionsIndex !== -1 && methodArgs.length > optionsIndex) {
41
+ const opts = methodArgs[optionsIndex];
42
+ if (opts && typeof opts === 'object') {
43
+ const { exact, checked, disabled, expanded, includeHidden, level, pressed, selected, ...rest } = opts;
44
+ methodArgs[optionsIndex] = rest;
45
+ }
46
+ }
34
47
  if (timeout !== undefined) {
35
48
  if (optionsIndex !== -1) {
36
49
  while (methodArgs.length < optionsIndex) {
@@ -65,9 +78,7 @@ function executeAction(prop, resolveLocatorFn, timeout, args) {
65
78
  await locator.focus();
66
79
  await locator.evaluate((el, val) => {
67
80
  const inputEl = el;
68
- const prototype = el.tagName === 'TEXTAREA'
69
- ? window.HTMLTextAreaElement.prototype
70
- : window.HTMLInputElement.prototype;
81
+ const prototype = el.tagName === 'TEXTAREA' ? window.HTMLTextAreaElement.prototype : window.HTMLInputElement.prototype;
71
82
  const descriptor = Object.getOwnPropertyDescriptor(prototype, 'value');
72
83
  if (descriptor && descriptor.set) {
73
84
  descriptor.set.call(inputEl, val);