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,1147 @@
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
36
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.getSelectorValue = getSelectorValue;
40
+ exports.findRegistryFile = findRegistryFile;
41
+ exports.findPlaywrightConfig = findPlaywrightConfig;
42
+ exports.parseRegistry = parseRegistry;
43
+ exports.matchDynamicEntry = matchDynamicEntry;
44
+ exports.writeRegistry = writeRegistry;
45
+ exports.findPageKey = findPageKey;
46
+ exports.toCamelCase = toCamelCase;
47
+ exports.findMatchInDict = findMatchInDict;
48
+ exports.findElementKey = findElementKey;
49
+ exports.formatActionCall = formatActionCall;
50
+ const fs = __importStar(require("fs"));
51
+ const path = __importStar(require("path"));
52
+ const key_utils_1 = require("./key-utils");
53
+ function getSelectorValue(selector) {
54
+ // 1. Try to find data-testid first
55
+ const testIdRegexes = [
56
+ /internal:testid=\[data-testid="([^"]+)"[si]?\]/,
57
+ /data-testid="([^"]+)"[si]?/,
58
+ /\[data-testid="([^"]+)"[si]?\]/,
59
+ /data-testid=([^\[\]\s]+)/
60
+ ];
61
+ for (const regex of testIdRegexes) {
62
+ const match = selector.match(regex);
63
+ if (match) {
64
+ let val = match[1];
65
+ val = val.replace(/^["']|["']$/g, '');
66
+ return { type: 'testId', val };
67
+ }
68
+ }
69
+ // 2. Playwright getByRole
70
+ const roleRegex = /internal:role=([a-zA-Z0-9_-]+)\[name="([^"]+)"i?\]/;
71
+ const roleMatch = selector.match(roleRegex);
72
+ if (roleMatch) {
73
+ let type = roleMatch[1];
74
+ if (type === 'img')
75
+ type = 'altText';
76
+ return { type, val: roleMatch[2] };
77
+ }
78
+ const roleSimpleRegex = /role=([a-zA-Z0-9_-]+)/;
79
+ const roleSimpleMatch = selector.match(roleSimpleRegex);
80
+ if (roleSimpleMatch) {
81
+ return { type: roleSimpleMatch[1], val: roleSimpleMatch[1] };
82
+ }
83
+ // 3. Playwright getByLabel
84
+ const labelRegex = /internal:label="([^"]+)"i?/;
85
+ const labelMatch = selector.match(labelRegex);
86
+ if (labelMatch) {
87
+ return { type: 'label', val: labelMatch[1] };
88
+ }
89
+ // 4. Playwright getByPlaceholder
90
+ const placeholderRegexes = [
91
+ /internal:placeholder="([^"]+)"i?/,
92
+ /internal:attr=\[placeholder="([^"]+)"[si]?\]/
93
+ ];
94
+ for (const regex of placeholderRegexes) {
95
+ const placeholderMatch = selector.match(regex);
96
+ if (placeholderMatch) {
97
+ return { type: 'placeholder', val: placeholderMatch[1] };
98
+ }
99
+ }
100
+ // 5. Playwright getByAltText
101
+ const altRegexes = [
102
+ /internal:alt="([^"]+)"i?/,
103
+ /internal:attr=\[alt="([^"]+)"[si]?\]/
104
+ ];
105
+ for (const regex of altRegexes) {
106
+ const altMatch = selector.match(regex);
107
+ if (altMatch) {
108
+ return { type: 'altText', val: altMatch[1] };
109
+ }
110
+ }
111
+ // 6. Playwright getByTitle
112
+ const titleRegexes = [
113
+ /internal:title="([^"]+)"i?/,
114
+ /internal:attr=\[title="([^"]+)"[si]?\]/
115
+ ];
116
+ for (const regex of titleRegexes) {
117
+ const titleMatch = selector.match(regex);
118
+ if (titleMatch) {
119
+ return { type: 'title', val: titleMatch[1] };
120
+ }
121
+ }
122
+ // 7. Playwright getByText
123
+ const textRegex = /(?:internal:text|text)="([^"]+)"i?/;
124
+ const textMatch = selector.match(textRegex);
125
+ if (textMatch) {
126
+ return { type: 'text', val: textMatch[1] };
127
+ }
128
+ const textSimpleRegex = /(?:internal:text|text)=([^"\s]+)/;
129
+ const textSimpleMatch = selector.match(textSimpleRegex);
130
+ if (textSimpleMatch) {
131
+ return { type: 'text', val: textSimpleMatch[1] };
132
+ }
133
+ // 8. Try to find ID selector
134
+ const idRegexes = [/id=([a-zA-Z0-9_-]+)/, /#([a-zA-Z0-9_-]+)/];
135
+ for (const regex of idRegexes) {
136
+ const match = selector.match(regex);
137
+ if (match) {
138
+ return { type: 'selector', val: `#${match[1]}` };
139
+ }
140
+ }
141
+ // 9. Try to find class selectors
142
+ const classRegexes = [/\.([a-zA-Z0-9_-]+)/];
143
+ for (const regex of classRegexes) {
144
+ const match = selector.match(regex);
145
+ if (match) {
146
+ return { type: 'selector', val: `.${match[1]}` };
147
+ }
148
+ }
149
+ // 10. Fallback to raw selector
150
+ return { type: 'selector', val: selector };
151
+ }
152
+ function findRegistryFile(dir) {
153
+ const queue = [dir];
154
+ while (queue.length > 0) {
155
+ const current = queue.shift();
156
+ try {
157
+ const files = fs.readdirSync(current);
158
+ for (const file of files) {
159
+ const fullPath = path.join(current, file);
160
+ if (file === 'node_modules' || file === '.git' || file === 'dist')
161
+ continue;
162
+ const stat = fs.statSync(fullPath);
163
+ if (stat.isDirectory()) {
164
+ queue.push(fullPath);
165
+ }
166
+ else if (file === 'registry.ts' || file === 'registry.js') {
167
+ try {
168
+ const content = fs.readFileSync(fullPath, 'utf8');
169
+ if (content.includes('createPageRegistry(')) {
170
+ return fullPath;
171
+ }
172
+ }
173
+ catch (e) { }
174
+ }
175
+ }
176
+ }
177
+ catch (e) { }
178
+ }
179
+ let parent = path.dirname(dir);
180
+ while (parent !== dir) {
181
+ const checkPath = path.join(parent, 'registry.ts');
182
+ if (fs.existsSync(checkPath)) {
183
+ try {
184
+ const content = fs.readFileSync(checkPath, 'utf8');
185
+ if (content.includes('createPageRegistry('))
186
+ return checkPath;
187
+ }
188
+ catch (e) { }
189
+ }
190
+ const checkPathSrc = path.join(parent, 'src', 'pages', 'registry.ts');
191
+ if (fs.existsSync(checkPathSrc)) {
192
+ try {
193
+ const content = fs.readFileSync(checkPathSrc, 'utf8');
194
+ if (content.includes('createPageRegistry('))
195
+ return checkPathSrc;
196
+ }
197
+ catch (e) { }
198
+ }
199
+ dir = parent;
200
+ parent = path.dirname(dir);
201
+ }
202
+ return null;
203
+ }
204
+ function findPlaywrightConfig(dir) {
205
+ const queue = [dir];
206
+ while (queue.length > 0) {
207
+ const current = queue.shift();
208
+ try {
209
+ const files = fs.readdirSync(current);
210
+ for (const file of files) {
211
+ if (file === 'node_modules' || file === '.git' || file === 'dist')
212
+ continue;
213
+ const fullPath = path.join(current, file);
214
+ const stat = fs.statSync(fullPath);
215
+ if (stat.isDirectory()) {
216
+ queue.push(fullPath);
217
+ }
218
+ else if (file === 'playwright.config.ts' || file === 'playwright.config.js') {
219
+ return fullPath;
220
+ }
221
+ }
222
+ }
223
+ catch (e) { }
224
+ }
225
+ let parent = path.dirname(dir);
226
+ while (parent !== dir) {
227
+ const tsPath = path.join(parent, 'playwright.config.ts');
228
+ const jsPath = path.join(parent, 'playwright.config.js');
229
+ if (fs.existsSync(tsPath))
230
+ return tsPath;
231
+ if (fs.existsSync(jsPath))
232
+ return jsPath;
233
+ dir = parent;
234
+ parent = path.dirname(dir);
235
+ }
236
+ return null;
237
+ }
238
+ function findRegistryCallBounds(content) {
239
+ const matchIndex = content.indexOf('createPageRegistry(');
240
+ if (matchIndex === -1)
241
+ return null;
242
+ const startIdx = matchIndex + 'createPageRegistry('.length;
243
+ let braceCount = 0;
244
+ for (let i = startIdx; i < content.length; i++) {
245
+ const char = content[i];
246
+ if (char === '(')
247
+ braceCount++;
248
+ else if (char === ')') {
249
+ if (braceCount === 0) {
250
+ return { startIdx, endIdx: i };
251
+ }
252
+ braceCount--;
253
+ }
254
+ }
255
+ return null;
256
+ }
257
+ function parseRegistry(filePath) {
258
+ try {
259
+ const content = fs.readFileSync(filePath, 'utf8');
260
+ const bounds = findRegistryCallBounds(content);
261
+ if (bounds) {
262
+ const objectLiteralText = content.substring(bounds.startIdx, bounds.endIdx).trim();
263
+ return new Function(`return (${objectLiteralText})`)();
264
+ }
265
+ }
266
+ catch (e) {
267
+ console.error('Error parsing registry.ts:', e);
268
+ }
269
+ return {};
270
+ }
271
+ function matchDynamicEntry(val, entry, isTestId) {
272
+ const pattern = isTestId ? entry.testId : entry.selector;
273
+ if (typeof pattern !== 'string')
274
+ return { matches: false };
275
+ const placeholders = Object.keys(entry).filter((k) => k !== 'testId' && k !== 'selector');
276
+ if (placeholders.length === 0)
277
+ return { matches: false };
278
+ const placeholder = placeholders[0];
279
+ let placeholderPattern = `{${placeholder}}`;
280
+ if (!pattern.includes(placeholderPattern)) {
281
+ placeholderPattern = placeholder;
282
+ }
283
+ const token = '__PLACEHOLDER_REGEX__';
284
+ const tempPattern = pattern.replace(placeholderPattern, token);
285
+ const escaped = tempPattern.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
286
+ const regexStr = '^' + escaped.replace(token, '([a-zA-Z0-9_ -]+)') + '$';
287
+ try {
288
+ const regex = new RegExp(regexStr);
289
+ const match = val.match(regex);
290
+ if (match) {
291
+ return {
292
+ matches: true,
293
+ matchedValue: match[1],
294
+ placeholderName: placeholder
295
+ };
296
+ }
297
+ }
298
+ catch (e) { }
299
+ return { matches: false };
300
+ }
301
+ function findCommonPrefix(values) {
302
+ if (values.length === 0)
303
+ return '';
304
+ const first = values[0];
305
+ const parts = first.split(/[-_]/);
306
+ let common = '';
307
+ for (let i = 0; i < parts.length; i++) {
308
+ const candidate = parts.slice(0, i + 1).join('-');
309
+ const matchesAll = values.every((v) => v.startsWith(candidate + '-') || v.startsWith(candidate + '_'));
310
+ if (matchesAll) {
311
+ common = candidate;
312
+ }
313
+ else {
314
+ break;
315
+ }
316
+ }
317
+ return common;
318
+ }
319
+ function collapsePageDict(dict, isTestId, keyReplacements) {
320
+ const result = {};
321
+ const dynamicEntries = {};
322
+ const staticEntries = {};
323
+ for (const k of Object.keys(dict)) {
324
+ if (typeof dict[k] === 'object' && dict[k] !== null) {
325
+ dynamicEntries[k] = dict[k];
326
+ }
327
+ else if (typeof dict[k] === 'string') {
328
+ staticEntries[k] = dict[k];
329
+ }
330
+ }
331
+ const collapsedKeys = new Set();
332
+ // 1. Try to merge static entries into existing dynamic entries first
333
+ for (const dk of Object.keys(dynamicEntries)) {
334
+ const entry = dynamicEntries[dk];
335
+ const placeholders = Object.keys(entry).filter((pk) => pk !== 'testId' && pk !== 'selector');
336
+ if (placeholders.length === 0)
337
+ continue;
338
+ const placeholder = placeholders[0];
339
+ for (const k of Object.keys(staticEntries)) {
340
+ const val = staticEntries[k];
341
+ const matchRes = matchDynamicEntry(val, entry, isTestId);
342
+ if (matchRes.matches && matchRes.matchedValue) {
343
+ if (!entry[placeholder].includes(matchRes.matchedValue)) {
344
+ entry[placeholder].push(matchRes.matchedValue);
345
+ }
346
+ collapsedKeys.add(k);
347
+ const capValue = matchRes.matchedValue.charAt(0).toUpperCase() + matchRes.matchedValue.slice(1);
348
+ let newKey = dk.replace(`{${placeholder}}`, capValue);
349
+ newKey = newKey.charAt(0).toLowerCase() + newKey.slice(1);
350
+ keyReplacements[k] = newKey;
351
+ }
352
+ }
353
+ }
354
+ const groups = {};
355
+ const staticKeys = Object.keys(staticEntries);
356
+ for (const k of staticKeys) {
357
+ if (collapsedKeys.has(k))
358
+ continue;
359
+ const val = staticEntries[k];
360
+ const isCssOrSpecial = val.includes('[') ||
361
+ val.includes(']') ||
362
+ val.includes('=') ||
363
+ val.includes(':') ||
364
+ val.includes('.') ||
365
+ val.includes('#');
366
+ const idSelectorMatch = val.match(/^#([a-zA-Z0-9_-]+)[-_]([a-zA-Z0-9_-]+)$/);
367
+ const classSelectorMatch = val.match(/^\.([a-zA-Z0-9_-]+)[-_]([a-zA-Z0-9_-]+)$/);
368
+ const testIdMatch = !isCssOrSpecial ? val.match(/^(.*?)[-_]([^-]+)$/) : null;
369
+ const attrMatch = val.match(/^\[([a-zA-Z0-9_-]+)="([^"]+)"\]$/);
370
+ const roleMatch = val.match(/^internal:role=([a-zA-Z0-9_-]+)\[name="([^"]+)"i\]$/);
371
+ const textMatch = val.match(/^(?:text|internal:text)=["']?([^"']+)["']?i?$/);
372
+ if (idSelectorMatch) {
373
+ const prefix = idSelectorMatch[1];
374
+ const suffix = idSelectorMatch[2];
375
+ const groupKey = `idSelector:${prefix}`;
376
+ if (!groups[groupKey]) {
377
+ groups[groupKey] = {
378
+ keys: [],
379
+ values: [],
380
+ prefix,
381
+ suffixPattern: 'idSelector'
382
+ };
383
+ }
384
+ groups[groupKey].keys.push(k);
385
+ groups[groupKey].values.push(suffix);
386
+ }
387
+ else if (classSelectorMatch) {
388
+ const prefix = classSelectorMatch[1];
389
+ const suffix = classSelectorMatch[2];
390
+ const groupKey = `classSelector:${prefix}`;
391
+ if (!groups[groupKey]) {
392
+ groups[groupKey] = {
393
+ keys: [],
394
+ values: [],
395
+ prefix,
396
+ suffixPattern: 'classSelector'
397
+ };
398
+ }
399
+ groups[groupKey].keys.push(k);
400
+ groups[groupKey].values.push(suffix);
401
+ }
402
+ else if (testIdMatch) {
403
+ const prefix = testIdMatch[1];
404
+ const suffix = testIdMatch[2];
405
+ const groupKey = `testId:${prefix}`;
406
+ if (!groups[groupKey]) {
407
+ groups[groupKey] = {
408
+ keys: [],
409
+ values: [],
410
+ prefix,
411
+ suffixPattern: 'testId'
412
+ };
413
+ }
414
+ groups[groupKey].keys.push(k);
415
+ groups[groupKey].values.push(suffix);
416
+ }
417
+ else if (attrMatch) {
418
+ const attrName = attrMatch[1];
419
+ const attrValue = attrMatch[2];
420
+ const groupKey = `attr:${attrName}`;
421
+ if (!groups[groupKey]) {
422
+ groups[groupKey] = {
423
+ keys: [],
424
+ values: [],
425
+ prefix: attrName,
426
+ suffixPattern: 'attr'
427
+ };
428
+ }
429
+ groups[groupKey].keys.push(k);
430
+ groups[groupKey].values.push(attrValue);
431
+ }
432
+ else if (roleMatch) {
433
+ const roleVal = roleMatch[1];
434
+ const nameVal = roleMatch[2];
435
+ const groupKey = `role:${roleVal}`;
436
+ if (!groups[groupKey]) {
437
+ groups[groupKey] = {
438
+ keys: [],
439
+ values: [],
440
+ prefix: roleVal,
441
+ suffixPattern: 'role'
442
+ };
443
+ }
444
+ groups[groupKey].keys.push(k);
445
+ groups[groupKey].values.push(nameVal);
446
+ }
447
+ else if (textMatch) {
448
+ const textValue = textMatch[1];
449
+ const groupKey = `text:text`;
450
+ if (!groups[groupKey]) {
451
+ groups[groupKey] = {
452
+ keys: [],
453
+ values: [],
454
+ prefix: 'text',
455
+ suffixPattern: 'text'
456
+ };
457
+ }
458
+ groups[groupKey].keys.push(k);
459
+ groups[groupKey].values.push(textValue);
460
+ }
461
+ }
462
+ for (const gk of Object.keys(groups)) {
463
+ const group = groups[gk];
464
+ if (group.keys.length >= 2 || (group.keys.length === 1 && group.values.every((v) => /^\d+$/.test(v)))) {
465
+ let placeholder = 'item';
466
+ if (group.values.every((v) => /^\d+$/.test(v))) {
467
+ placeholder = 'id';
468
+ }
469
+ else if (group.prefix.toLowerCase().includes('filter') ||
470
+ group.prefix.toLowerCase().includes('button') ||
471
+ group.prefix.toLowerCase().includes('btn')) {
472
+ placeholder = 'btn';
473
+ }
474
+ let dynamicKey = '';
475
+ let entry = {};
476
+ if (group.suffixPattern === 'testId') {
477
+ dynamicKey = toCamelCase(group.prefix) + `{${placeholder}}`;
478
+ entry = {
479
+ [placeholder]: group.values,
480
+ testId: group.prefix + '-' + placeholder
481
+ };
482
+ }
483
+ else if (group.suffixPattern === 'idSelector') {
484
+ dynamicKey = toCamelCase(group.prefix) + `{${placeholder}}`;
485
+ entry = {
486
+ [placeholder]: group.values,
487
+ selector: `#${group.prefix}-{${placeholder}}`
488
+ };
489
+ }
490
+ else if (group.suffixPattern === 'classSelector') {
491
+ dynamicKey = toCamelCase(group.prefix) + `{${placeholder}}`;
492
+ entry = {
493
+ [placeholder]: group.values,
494
+ selector: `.${group.prefix}-{${placeholder}}`
495
+ };
496
+ }
497
+ else if (group.suffixPattern === 'attr') {
498
+ const commonPrefix = findCommonPrefix(group.values);
499
+ if (commonPrefix) {
500
+ dynamicKey = toCamelCase(commonPrefix) + `{${placeholder}}`;
501
+ entry = {
502
+ [placeholder]: group.values.map((v) => v.substring(commonPrefix.length + 1)),
503
+ selector: `[${group.prefix}="${commonPrefix}-{${placeholder}}"]`
504
+ };
505
+ }
506
+ else {
507
+ dynamicKey = `{${placeholder}}`;
508
+ entry = {
509
+ [placeholder]: group.values,
510
+ selector: `[${group.prefix}="{${placeholder}}"]`
511
+ };
512
+ }
513
+ }
514
+ else if (group.suffixPattern === 'role') {
515
+ const placeholder = group.prefix === 'button' ? 'btn' : 'item';
516
+ dynamicKey = `{${placeholder}}`;
517
+ entry = {
518
+ [placeholder]: group.values,
519
+ selector: `internal:role=${group.prefix}[name="{${placeholder}}"i]`
520
+ };
521
+ }
522
+ else if (group.suffixPattern === 'text') {
523
+ dynamicKey = `{${placeholder}}`;
524
+ entry = {
525
+ [placeholder]: group.values,
526
+ selector: `text="{${placeholder}}"`
527
+ };
528
+ }
529
+ if (dynamicKey) {
530
+ dynamicEntries[dynamicKey] = entry;
531
+ group.keys.forEach((oldKey, idx) => {
532
+ collapsedKeys.add(oldKey);
533
+ const val = (entry[placeholder] ? entry[placeholder][idx] : group.values[idx]);
534
+ let newKey = '';
535
+ if (dynamicKey === `{${placeholder}}`) {
536
+ newKey = val;
537
+ }
538
+ else {
539
+ const capValue = val.charAt(0).toUpperCase() + val.slice(1);
540
+ newKey = dynamicKey.replace(`{${placeholder}}`, capValue);
541
+ newKey = newKey.charAt(0).toLowerCase() + newKey.slice(1);
542
+ }
543
+ keyReplacements[oldKey] = newKey;
544
+ });
545
+ }
546
+ }
547
+ }
548
+ for (const k of Object.keys(dict)) {
549
+ if (collapsedKeys.has(k))
550
+ continue;
551
+ if (dynamicEntries[k]) {
552
+ result[k] = dynamicEntries[k];
553
+ }
554
+ else {
555
+ result[k] = dict[k];
556
+ }
557
+ }
558
+ for (const k of Object.keys(dynamicEntries)) {
559
+ if (!result[k]) {
560
+ result[k] = dynamicEntries[k];
561
+ }
562
+ }
563
+ return result;
564
+ }
565
+ function writeRegistry(filePath, registryObj, overrideMode, usedPageKeys) {
566
+ try {
567
+ const keyReplacements = {};
568
+ const codegenKeys = Object.keys(registryObj).filter((k) => {
569
+ const pageConfig = registryObj[k];
570
+ const usedSet = usedPageKeys ? (usedPageKeys instanceof Set ? usedPageKeys : new Set(usedPageKeys)) : new Set();
571
+ const isUsed = usedSet.has(k);
572
+ if (pageConfig && !isUsed) {
573
+ let hasLocators = false;
574
+ for (const sk of Object.keys(pageConfig)) {
575
+ if (sk !== 'url' && pageConfig[sk] && Object.keys(pageConfig[sk]).length > 0) {
576
+ hasLocators = true;
577
+ break;
578
+ }
579
+ }
580
+ if (!hasLocators)
581
+ return false;
582
+ }
583
+ const isDefaultCodegen = k.startsWith('codegen_') || k === 'codegenPage';
584
+ if (isUsed) {
585
+ return true;
586
+ }
587
+ if (overrideMode) {
588
+ return true;
589
+ }
590
+ return isDefaultCodegen;
591
+ });
592
+ for (const codegenKey of codegenKeys) {
593
+ const pageConfig = registryObj[codegenKey];
594
+ if (pageConfig) {
595
+ if (pageConfig.testId) {
596
+ pageConfig.testId = collapsePageDict(pageConfig.testId, true, keyReplacements);
597
+ }
598
+ if (pageConfig.testIds) {
599
+ pageConfig.testIds = collapsePageDict(pageConfig.testIds, true, keyReplacements);
600
+ }
601
+ if (pageConfig.selector) {
602
+ pageConfig.selector = collapsePageDict(pageConfig.selector, false, keyReplacements);
603
+ }
604
+ if (pageConfig.selectors) {
605
+ pageConfig.selectors = collapsePageDict(pageConfig.selectors, false, keyReplacements);
606
+ }
607
+ }
608
+ }
609
+ let content = fs.readFileSync(filePath, 'utf8');
610
+ const serialize = (obj, indent = 2, isTestIdsOrSelectors = false) => {
611
+ const spaces = ' '.repeat(indent);
612
+ if (obj === null)
613
+ return 'null';
614
+ if (obj === undefined)
615
+ return 'undefined';
616
+ if (typeof obj === 'string') {
617
+ return `'${obj.replace(/'/g, "\\'")}'`;
618
+ }
619
+ if (typeof obj === 'number' || typeof obj === 'boolean') {
620
+ return String(obj);
621
+ }
622
+ if (Array.isArray(obj)) {
623
+ return '[' + obj.map((x) => serialize(x, indent, false)).join(', ') + ']';
624
+ }
625
+ if (typeof obj === 'object') {
626
+ let keys = Object.keys(obj);
627
+ if (isTestIdsOrSelectors) {
628
+ keys = keys.sort((a, b) => a.localeCompare(b));
629
+ }
630
+ else if (indent === 4) {
631
+ const order = [
632
+ 'url', 'testId', 'testIds', 'selector', 'selectors',
633
+ 'text', 'label', 'title', 'placeholder', 'altText',
634
+ 'button', 'checkbox', 'radio', 'heading', 'link', 'dialog',
635
+ 'textbox', 'searchbox', 'combobox', 'list', 'listbox',
636
+ 'menu', 'menuitem', 'option', 'row', 'cell', 'grid', 'gridcell',
637
+ 'tab', 'tabpanel', 'switch', 'progressbar', 'status', 'tooltip',
638
+ 'tree', 'treeitem', 'banner', 'navigation', 'article', 'main', 'form', 'region'
639
+ ];
640
+ keys = keys.sort((a, b) => {
641
+ const idxA = order.indexOf(a);
642
+ const idxB = order.indexOf(b);
643
+ if (idxA !== -1 && idxB !== -1)
644
+ return idxA - idxB;
645
+ if (idxA !== -1)
646
+ return -1;
647
+ if (idxB !== -1)
648
+ return 1;
649
+ return a.localeCompare(b);
650
+ });
651
+ }
652
+ if (keys.length === 0)
653
+ return '{}';
654
+ let res = '{\n';
655
+ keys.forEach((key, index) => {
656
+ const formattedKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : `'${key.replace(/'/g, "\\'")}'`;
657
+ const nextIsTestIdsOrSelectors = isTestIdsOrSelectors || key === 'testId' || key === 'testIds' || key === 'selector' || key === 'selectors';
658
+ res += `${spaces} ${formattedKey}: ${serialize(obj[key], indent + 2, nextIsTestIdsOrSelectors)}${index < keys.length - 1 ? ',\n' : '\n'}`;
659
+ });
660
+ res += `${spaces}}`;
661
+ return res;
662
+ }
663
+ return 'undefined';
664
+ };
665
+ for (const codegenKey of codegenKeys) {
666
+ const escapedKey = codegenKey.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
667
+ const keyPattern = new RegExp(`(['"\`]?${escapedKey}['"\`]?\\s*:\\s*\\{)`);
668
+ const match = content.match(keyPattern);
669
+ if (match && match.index !== undefined) {
670
+ const startIdx = match.index + match[0].length - 1;
671
+ let braceCount = 0;
672
+ let endIdx = -1;
673
+ for (let i = startIdx; i < content.length; i++) {
674
+ if (content[i] === '{')
675
+ braceCount++;
676
+ else if (content[i] === '}') {
677
+ braceCount--;
678
+ if (braceCount === 0) {
679
+ endIdx = i + 1;
680
+ break;
681
+ }
682
+ }
683
+ }
684
+ if (endIdx !== -1) {
685
+ const updatedObjectText = serialize(registryObj[codegenKey], 2);
686
+ content = content.substring(0, startIdx) + updatedObjectText + content.substring(endIdx);
687
+ }
688
+ }
689
+ else {
690
+ const bounds = findRegistryCallBounds(content);
691
+ if (bounds) {
692
+ const lastBraceIdx = content.lastIndexOf('}', bounds.endIdx);
693
+ if (lastBraceIdx !== -1) {
694
+ const formattedKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(codegenKey)
695
+ ? codegenKey
696
+ : `'${codegenKey}'`;
697
+ const serializedPage = ` ${formattedKey}: ${serialize(registryObj[codegenKey], 2)}`;
698
+ let lastCharIdx = lastBraceIdx - 1;
699
+ while (lastCharIdx > bounds.startIdx && /\s/.test(content[lastCharIdx])) {
700
+ lastCharIdx--;
701
+ }
702
+ if (content[lastCharIdx] === '}' && content[lastCharIdx + 1] !== ',') {
703
+ content = content.substring(0, lastCharIdx + 1) + ',\n' + serializedPage + '\n' + content.substring(lastBraceIdx);
704
+ }
705
+ else {
706
+ const beforeBrace = content.substring(bounds.startIdx, lastBraceIdx).trim();
707
+ const needsComma = beforeBrace.length > 0 && !beforeBrace.endsWith(',') && !beforeBrace.endsWith('{');
708
+ const insertText = (needsComma ? ',\n' : '\n') + serializedPage + '\n';
709
+ content = content.substring(0, lastBraceIdx) + insertText + content.substring(lastBraceIdx);
710
+ }
711
+ }
712
+ }
713
+ }
714
+ }
715
+ fs.writeFileSync(filePath, content, 'utf8');
716
+ if (Object.keys(keyReplacements).length > 0) {
717
+ const testsDir = path.join(path.dirname(filePath), '../tests');
718
+ if (fs.existsSync(testsDir)) {
719
+ const files = fs.readdirSync(testsDir);
720
+ for (const file of files) {
721
+ if (file.endsWith('.spec.ts') || file.endsWith('.test.ts')) {
722
+ const specPath = path.join(testsDir, file);
723
+ let specContent = fs.readFileSync(specPath, 'utf8');
724
+ let modified = false;
725
+ for (const oldKey of Object.keys(keyReplacements)) {
726
+ const newKey = keyReplacements[oldKey];
727
+ const regex = new RegExp(`(['"\`])${oldKey}(['"\`])`, 'g');
728
+ const before = specContent;
729
+ specContent = specContent.replace(regex, `$1${newKey}$2`);
730
+ if (specContent !== before)
731
+ modified = true;
732
+ }
733
+ if (modified) {
734
+ fs.writeFileSync(specPath, specContent, 'utf8');
735
+ }
736
+ }
737
+ }
738
+ }
739
+ }
740
+ return keyReplacements;
741
+ }
742
+ catch (e) {
743
+ console.error('Error writing registry.ts:', e);
744
+ }
745
+ return {};
746
+ }
747
+ function findPageKey(url, title, registryObj, overrideMode) {
748
+ let pathname = '';
749
+ let hashPath = '';
750
+ try {
751
+ const u = new URL(url);
752
+ pathname = u.pathname;
753
+ if (u.hash && u.hash.startsWith('#/')) {
754
+ hashPath = u.hash.slice(1);
755
+ }
756
+ }
757
+ catch (e) {
758
+ pathname = url || '';
759
+ }
760
+ const cleanPath = (p) => {
761
+ let result = p.split('?')[0].split('#')[0];
762
+ if (result.startsWith('/'))
763
+ result = result.substring(1);
764
+ if (result.endsWith('/'))
765
+ result = result.slice(0, -1);
766
+ return result;
767
+ };
768
+ const effectivePath = (hashPath && hashPath !== '/' && hashPath !== '')
769
+ ? cleanPath(hashPath)
770
+ : cleanPath(pathname);
771
+ for (const key of Object.keys(registryObj)) {
772
+ const pageConfig = registryObj[key];
773
+ if (pageConfig && pageConfig.url) {
774
+ let configUrl = pageConfig.url;
775
+ if (configUrl.startsWith('/'))
776
+ configUrl = configUrl.substring(1);
777
+ if (configUrl.endsWith('/'))
778
+ configUrl = configUrl.slice(0, -1);
779
+ if (configUrl === effectivePath) {
780
+ const isCodegen = key.startsWith('codegen_') || key === 'codegenPage';
781
+ if (!overrideMode && !isCodegen)
782
+ continue;
783
+ if (!effectivePath && isCodegen)
784
+ continue;
785
+ return key;
786
+ }
787
+ }
788
+ }
789
+ let keyBase = '';
790
+ if (effectivePath) {
791
+ const segments = effectivePath.split('/').filter(Boolean);
792
+ keyBase = segments
793
+ .map((seg, idx) => {
794
+ const parts = seg.split(/[^a-zA-Z0-9]+/).filter(Boolean);
795
+ if (parts.length === 0)
796
+ return '';
797
+ return parts
798
+ .map((part, partIdx) => {
799
+ if (idx === 0 && partIdx === 0) {
800
+ return part.charAt(0).toLowerCase() + part.slice(1);
801
+ }
802
+ return part.charAt(0).toUpperCase() + part.slice(1);
803
+ })
804
+ .join('');
805
+ })
806
+ .join('');
807
+ }
808
+ if (!keyBase && title) {
809
+ const firstSegment = title.split(/[|\u2014\-:]/)[0].trim();
810
+ const cleanTitle = (firstSegment || title).replace(/[^a-zA-Z0-9\s]/g, '').trim();
811
+ const words = cleanTitle.split(/\s+/).filter(Boolean);
812
+ keyBase = words
813
+ .map((w, idx) => {
814
+ const clean = w.replace(/[^a-zA-Z0-9]/g, '');
815
+ if (idx === 0)
816
+ return clean.charAt(0).toLowerCase() + clean.slice(1);
817
+ return clean.charAt(0).toUpperCase() + clean.slice(1);
818
+ })
819
+ .join('');
820
+ }
821
+ if (!keyBase) {
822
+ keyBase = 'home';
823
+ }
824
+ if (overrideMode) {
825
+ return keyBase;
826
+ }
827
+ return `codegen_${keyBase}`;
828
+ }
829
+ function toCamelCase(str) {
830
+ return (0, key_utils_1.toRegistryKey)(str);
831
+ }
832
+ function normalizePageKey(key) {
833
+ if (key.startsWith('worker') && key.length > 6) {
834
+ return key.slice(6).charAt(0).toLowerCase() + key.slice(7);
835
+ }
836
+ return key;
837
+ }
838
+ function findMatchInDict(val, strategyType, pageKey, registryObj, overrideMode) {
839
+ const getExpandedKey = (dynamicKey, placeholder, value) => {
840
+ const isPurePlaceholder = dynamicKey === `{${placeholder}}`;
841
+ let capValue = '';
842
+ if (isPurePlaceholder) {
843
+ capValue = value;
844
+ }
845
+ else {
846
+ const words = value.split(/[^a-zA-Z0-9]/).filter(Boolean);
847
+ capValue = words.map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join('');
848
+ }
849
+ return dynamicKey.replace(`{${placeholder}}`, capValue);
850
+ };
851
+ let targetPageKey = pageKey;
852
+ for (const k of Object.keys(registryObj)) {
853
+ if (normalizePageKey(k) === normalizePageKey(pageKey)) {
854
+ targetPageKey = k;
855
+ break;
856
+ }
857
+ }
858
+ const pageConfig = registryObj[targetPageKey] || {};
859
+ const searchConfig = (config, pk) => {
860
+ if (strategyType === 'testId') {
861
+ const dict = config.testId || config.testIds || {};
862
+ for (const k of Object.keys(dict)) {
863
+ const entry = dict[k];
864
+ if (typeof entry === 'object' && entry !== null) {
865
+ const { matches, matchedValue, placeholderName } = matchDynamicEntry(val, entry, true);
866
+ if (matches && matchedValue && placeholderName) {
867
+ const arr = entry[placeholderName] || [];
868
+ if (!arr.includes(matchedValue)) {
869
+ entry[placeholderName] = [...arr, matchedValue];
870
+ }
871
+ const expandedKey = getExpandedKey(k, placeholderName, matchedValue);
872
+ return { pageKey: pk, elementKey: expandedKey, val, type: 'testId', isNew: false };
873
+ }
874
+ }
875
+ else if (entry === val) {
876
+ return { pageKey: pk, elementKey: k, val, type: 'testId', isNew: false };
877
+ }
878
+ }
879
+ }
880
+ else if (strategyType === 'selector') {
881
+ const dict = config.selector || config.selectors || {};
882
+ for (const k of Object.keys(dict)) {
883
+ const entry = dict[k];
884
+ if (typeof entry === 'object' && entry !== null) {
885
+ const { matches, matchedValue, placeholderName } = matchDynamicEntry(val, entry, false);
886
+ if (matches && matchedValue && placeholderName) {
887
+ const arr = entry[placeholderName] || [];
888
+ if (!arr.includes(matchedValue)) {
889
+ entry[placeholderName] = [...arr, matchedValue];
890
+ }
891
+ const expandedKey = getExpandedKey(k, placeholderName, matchedValue);
892
+ return { pageKey: pk, elementKey: expandedKey, val, type: 'selector', isNew: false };
893
+ }
894
+ }
895
+ else if (entry === val) {
896
+ return { pageKey: pk, elementKey: k, val, type: 'selector', isNew: false };
897
+ }
898
+ }
899
+ }
900
+ else {
901
+ const arr = config[strategyType];
902
+ if (Array.isArray(arr)) {
903
+ if (arr.includes(val)) {
904
+ const elementKey = val;
905
+ return { pageKey: pk, elementKey, val, type: strategyType, isNew: false };
906
+ }
907
+ }
908
+ }
909
+ return null;
910
+ };
911
+ const targetMatch = searchConfig(pageConfig, targetPageKey);
912
+ if (targetMatch)
913
+ return targetMatch;
914
+ for (const pk of Object.keys(registryObj)) {
915
+ if (normalizePageKey(pk) === normalizePageKey(pageKey))
916
+ continue;
917
+ const isCurrentCodegen = pageKey.startsWith('codegen_') || pageKey === 'codegenPage';
918
+ const isOtherCodegen = pk.startsWith('codegen_') || pk === 'codegenPage';
919
+ if (isCurrentCodegen && isOtherCodegen)
920
+ continue;
921
+ const config = registryObj[pk] || {};
922
+ const match = searchConfig(config, pk);
923
+ if (match)
924
+ return match;
925
+ }
926
+ return null;
927
+ }
928
+ function findElementKey(selector, pageKey, registryObj, overrideMode, extra) {
929
+ let { type, val } = getSelectorValue(selector);
930
+ if (extra?.overrideType) {
931
+ type = extra.overrideType;
932
+ }
933
+ // 1. Try matching with the selector itself first
934
+ const selectorMatch = findMatchInDict(val, type, pageKey, registryObj, overrideMode);
935
+ if (selectorMatch)
936
+ return selectorMatch;
937
+ // 1.5. Check if the value exists in ANY other strategy array/object under the page config to avoid duplicates and recreation
938
+ const pageConfig = registryObj[pageKey] || {};
939
+ for (const k of Object.keys(pageConfig)) {
940
+ if (k === 'url')
941
+ continue;
942
+ const match = findMatchInDict(val, k, pageKey, registryObj, overrideMode);
943
+ if (match) {
944
+ return match;
945
+ }
946
+ }
947
+ // 2. Try matching targetTestId (if any) against testIds in registry
948
+ if (extra?.targetTestId) {
949
+ const testIdMatch = findMatchInDict(extra.targetTestId, 'testId', pageKey, registryObj, overrideMode);
950
+ if (testIdMatch)
951
+ return testIdMatch;
952
+ }
953
+ // 3. Try matching targetId (if any) against selectors/testIds
954
+ if (extra?.targetId) {
955
+ const idSelectorMatch = findMatchInDict(extra.targetId, 'selector', pageKey, registryObj, overrideMode);
956
+ if (idSelectorMatch)
957
+ return idSelectorMatch;
958
+ const idTestIdMatch = findMatchInDict(extra.targetId, 'testId', pageKey, registryObj, overrideMode);
959
+ if (idTestIdMatch)
960
+ return idTestIdMatch;
961
+ }
962
+ // 4. Try matching targetParentId (if any) against selectors/testIds
963
+ if (extra?.targetParentId) {
964
+ const pIdSelectorMatch = findMatchInDict(extra.targetParentId, 'selector', pageKey, registryObj, overrideMode);
965
+ if (pIdSelectorMatch)
966
+ return pIdSelectorMatch;
967
+ }
968
+ // Already declared above: pageConfig
969
+ let baseKey = (type === 'testId' || type === 'selector') ? toCamelCase(val) : val;
970
+ if (!baseKey)
971
+ baseKey = 'element';
972
+ let finalKey = baseKey;
973
+ let counter = 1;
974
+ const existingKeys = new Set();
975
+ for (const key of Object.keys(pageConfig)) {
976
+ const entry = pageConfig[key];
977
+ if (Array.isArray(entry)) {
978
+ entry.forEach(v => existingKeys.add(v));
979
+ }
980
+ else if (typeof entry === 'object' && entry !== null) {
981
+ Object.keys(entry).forEach(k => existingKeys.add(k));
982
+ }
983
+ }
984
+ while (existingKeys.has(finalKey)) {
985
+ finalKey = baseKey + counter;
986
+ counter++;
987
+ }
988
+ return { pageKey, elementKey: finalKey, val, type, isNew: true };
989
+ }
990
+ function formatActionCall(pageKey, elementKey, action, isTextSelector = false, textValue) {
991
+ const getLocatorExpression = () => {
992
+ if (isTextSelector && textValue) {
993
+ let expr = `${pageKey}.page.getByText('${textValue.replace(/'/g, "\\'")}')`;
994
+ if (action.nth !== undefined && action.nth !== 0) {
995
+ expr += `.nth(${action.nth})`;
996
+ }
997
+ return expr;
998
+ }
999
+ return null;
1000
+ };
1001
+ // Escape single quotes in elementKey so generated code like click('I\'m Feeling Lucky') is valid JS
1002
+ const safeKey = elementKey.replace(/'/g, "\\'");
1003
+ switch (action.name) {
1004
+ case 'click': {
1005
+ let method = 'click';
1006
+ if (action.clickCount === 2)
1007
+ method = 'dblclick';
1008
+ let opts = [];
1009
+ if (action.modifiers && action.modifiers.length) {
1010
+ opts.push(`modifiers: [${action.modifiers.map((m) => `'${m}'`).join(', ')}]`);
1011
+ }
1012
+ const locatorExpr = getLocatorExpression();
1013
+ if (locatorExpr) {
1014
+ const optsStr = opts.length ? `{ ${opts.join(', ')} }` : '';
1015
+ return ` await ${locatorExpr}.${method}(${optsStr});`;
1016
+ }
1017
+ if (action.nth !== undefined && action.nth !== 0) {
1018
+ opts.push(`nth: ${action.nth}`);
1019
+ }
1020
+ const optsStr = opts.length ? `, { ${opts.join(', ')} }` : '';
1021
+ return ` await ${pageKey}.${method}('${safeKey}'${optsStr});`;
1022
+ }
1023
+ case 'hover': {
1024
+ const locatorExpr = getLocatorExpression();
1025
+ if (locatorExpr) {
1026
+ return ` await ${locatorExpr}.hover();`;
1027
+ }
1028
+ const optsStr = action.nth !== undefined && action.nth !== 0 ? `, { nth: ${action.nth} }` : '';
1029
+ return ` await ${pageKey}.hover('${safeKey}'${optsStr});`;
1030
+ }
1031
+ case 'check': {
1032
+ const locatorExpr = getLocatorExpression();
1033
+ if (locatorExpr) {
1034
+ return ` await ${locatorExpr}.check();`;
1035
+ }
1036
+ const optsStr = action.nth !== undefined && action.nth !== 0 ? `, { nth: ${action.nth} }` : '';
1037
+ return ` await ${pageKey}.check('${safeKey}'${optsStr});`;
1038
+ }
1039
+ case 'uncheck': {
1040
+ const locatorExpr = getLocatorExpression();
1041
+ if (locatorExpr) {
1042
+ return ` await ${locatorExpr}.uncheck();`;
1043
+ }
1044
+ const optsStr = action.nth !== undefined && action.nth !== 0 ? `, { nth: ${action.nth} }` : '';
1045
+ return ` await ${pageKey}.uncheck('${safeKey}'${optsStr});`;
1046
+ }
1047
+ case 'fill': {
1048
+ const locatorExpr = getLocatorExpression();
1049
+ if (locatorExpr) {
1050
+ return ` await ${locatorExpr}.fill('${action.text.replace(/'/g, "\\'")}');`;
1051
+ }
1052
+ const optsStr = action.nth !== undefined && action.nth !== 0 ? `, { nth: ${action.nth} }` : '';
1053
+ return ` await ${pageKey}.fill('${safeKey}', '${action.text.replace(/'/g, "\\'")}'${optsStr});`;
1054
+ }
1055
+ case 'setInputFiles': {
1056
+ const locatorExpr = getLocatorExpression();
1057
+ if (locatorExpr) {
1058
+ return ` await ${locatorExpr}.setInputFiles(${JSON.stringify(action.files)});`;
1059
+ }
1060
+ const optsStr = action.nth !== undefined && action.nth !== 0 ? `, { nth: ${action.nth} }` : '';
1061
+ return ` await ${pageKey}.setInputFiles('${safeKey}', ${JSON.stringify(action.files)}${optsStr});`;
1062
+ }
1063
+ case 'press': {
1064
+ const modifiers = Array.isArray(action.modifiers) ? action.modifiers : [];
1065
+ const shortcut = [...modifiers, action.key].join('+');
1066
+ const locatorExpr = getLocatorExpression();
1067
+ if (locatorExpr) {
1068
+ return ` await ${locatorExpr}.press('${shortcut}');`;
1069
+ }
1070
+ const optsStr = action.nth !== undefined && action.nth !== 0 ? `, { nth: ${action.nth} }` : '';
1071
+ return ` await ${pageKey}.press('${safeKey}', '${shortcut}'${optsStr});`;
1072
+ }
1073
+ case 'navigate':
1074
+ return ` await ${pageKey}.goto();`;
1075
+ case 'select': {
1076
+ const locatorExpr = getLocatorExpression();
1077
+ if (locatorExpr) {
1078
+ return ` await ${locatorExpr}.selectOption(${JSON.stringify(action.options)});`;
1079
+ }
1080
+ const optsStr = action.nth !== undefined && action.nth !== 0 ? `, { nth: ${action.nth} }` : '';
1081
+ return ` await ${pageKey}.selectOption('${safeKey}', ${JSON.stringify(action.options)}${optsStr});`;
1082
+ }
1083
+ case 'assertText': {
1084
+ const locatorExpr = getLocatorExpression();
1085
+ if (locatorExpr) {
1086
+ return ` await expect(${locatorExpr}).${action.substring ? 'toContainText' : 'toHaveText'}('${action.text.replace(/'/g, "\\'")}');`;
1087
+ }
1088
+ const opts = [];
1089
+ if (action.nth !== undefined && action.nth !== 0)
1090
+ opts.push(`nth: ${action.nth}`);
1091
+ const optsStr = opts.length ? `, { ${opts.join(', ')} }` : '';
1092
+ return ` await ${pageKey}.verify('${safeKey}'${optsStr}).${action.substring ? 'toContainText' : 'toHaveText'}('${action.text.replace(/'/g, "\\'")}');`;
1093
+ }
1094
+ case 'assertChecked': {
1095
+ const locatorExpr = getLocatorExpression();
1096
+ if (locatorExpr) {
1097
+ return ` await expect(${locatorExpr})${action.checked ? '' : '.not'}.toBeChecked();`;
1098
+ }
1099
+ const opts = [];
1100
+ if (action.nth !== undefined && action.nth !== 0)
1101
+ opts.push(`nth: ${action.nth}`);
1102
+ const optsStr = opts.length ? `, { ${opts.join(', ')} }` : '';
1103
+ return ` await ${pageKey}.verify('${safeKey}'${optsStr})${action.checked ? '' : '.not'}.toBeChecked();`;
1104
+ }
1105
+ case 'assertVisible': {
1106
+ const locatorExpr = getLocatorExpression();
1107
+ if (locatorExpr) {
1108
+ return ` await expect(${locatorExpr}).toBeVisible();`;
1109
+ }
1110
+ const opts = [];
1111
+ if (action.nth !== undefined && action.nth !== 0)
1112
+ opts.push(`nth: ${action.nth}`);
1113
+ const optsStr = opts.length ? `, { ${opts.join(', ')} }` : '';
1114
+ return ` await ${pageKey}.verify('${safeKey}'${optsStr});`;
1115
+ }
1116
+ case 'assertValue': {
1117
+ const locatorExpr = getLocatorExpression();
1118
+ if (locatorExpr) {
1119
+ const assertion = action.value ? `toHaveValue('${action.value.replace(/'/g, "\\'")}')` : `toBeEmpty()`;
1120
+ return ` await expect(${locatorExpr}).${assertion};`;
1121
+ }
1122
+ const opts = [];
1123
+ if (action.nth !== undefined && action.nth !== 0)
1124
+ opts.push(`nth: ${action.nth}`);
1125
+ const optsStr = opts.length ? `, { ${opts.join(', ')} }` : '';
1126
+ const assertion = action.value ? `toHaveValue('${action.value.replace(/'/g, "\\'")}')` : `toBeEmpty()`;
1127
+ return ` await ${pageKey}.verify('${safeKey}'${optsStr}).${assertion};`;
1128
+ }
1129
+ case 'assertSnapshot': {
1130
+ const locatorExpr = getLocatorExpression();
1131
+ if (locatorExpr) {
1132
+ return ` await expect(${locatorExpr}).toMatchAriaSnapshot(\`\n${action.ariaSnapshot}\`);`;
1133
+ }
1134
+ const opts = [];
1135
+ if (action.nth !== undefined && action.nth !== 0)
1136
+ opts.push(`nth: ${action.nth}`);
1137
+ const optsStr = opts.length ? `, { ${opts.join(', ')} }` : '';
1138
+ return ` await ${pageKey}.verify('${safeKey}'${optsStr}).toMatchAriaSnapshot(\`\n${action.ariaSnapshot}\`);`;
1139
+ }
1140
+ default:
1141
+ return ` // Unsupported action: ${action.name} on ${elementKey}`;
1142
+ }
1143
+ }
1144
+ __exportStar(require("./config"), exports);
1145
+ __exportStar(require("./generator/index"), exports);
1146
+ __exportStar(require("./types"), exports);
1147
+ __exportStar(require("./scorer"), exports);