@cementic/cementic-test 0.2.10 → 0.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/dist/{chunk-3TBS4PBV.js → chunk-RG26I5FB.js} +64 -30
- package/dist/chunk-RG26I5FB.js.map +1 -0
- package/dist/cli.js +374 -63
- package/dist/cli.js.map +1 -1
- package/dist/{gen-YF22KYYU.js → gen-6Y65IYXO.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-3TBS4PBV.js.map +0 -1
- /package/dist/{gen-YF22KYYU.js.map → gen-6Y65IYXO.js.map} +0 -0
package/README.md
CHANGED
|
@@ -365,6 +365,21 @@ And start automating.
|
|
|
365
365
|
|
|
366
366
|
## Changelog
|
|
367
367
|
|
|
368
|
+
### v0.2.12
|
|
369
|
+
|
|
370
|
+
- made both AI generation paths intent-first so markdown and capture-based scenario generation follow the same scope and presence-only rules
|
|
371
|
+
- tightened capture-based scenario generation to preserve presence-only checks as visibility assertions, honor intent-based selector fallback, and avoid generic `'value'` placeholders
|
|
372
|
+
- added regression coverage for the new markdown prompt contract and capture-path intent enforcement
|
|
373
|
+
- breaking change: none
|
|
374
|
+
|
|
375
|
+
### v0.2.11
|
|
376
|
+
|
|
377
|
+
- AI no longer writes `'value'` as a step input and now prefers matching `CT_VAR_*` references or `test-{fieldname}` fallbacks
|
|
378
|
+
- fixed `ct gen` so generic fill steps read matching `CT_VAR_*` values from the environment and emit env-backed constants only when they are actually needed
|
|
379
|
+
- fixed generated `toHaveValue(...)` assertions so they reuse the same emitted fill value for selector-backed form fields
|
|
380
|
+
- added a generated spec header comment that lists required `CT_VAR_*` variables with inline usage examples
|
|
381
|
+
- breaking change: none
|
|
382
|
+
|
|
368
383
|
### v0.2.10
|
|
369
384
|
|
|
370
385
|
- fixed `ct gen` so selector-hinted fields like `#username` and `#password` infer matching `CT_VAR_*` constants instead of leaving `.fill('value')` placeholders behind
|
|
@@ -117,6 +117,32 @@ function isGenericFallbackValue(value) {
|
|
|
117
117
|
if (!value) return true;
|
|
118
118
|
return /^(?:value|text|input|option|selection|selected value|default)$/i.test(value.trim());
|
|
119
119
|
}
|
|
120
|
+
function extractCtVarTemplate(value) {
|
|
121
|
+
const match = value?.trim().match(/^\$\{(CT_VAR_[A-Z0-9_]+)\}$/);
|
|
122
|
+
return match?.[1];
|
|
123
|
+
}
|
|
124
|
+
function placeholderTokenFromSuffix(value) {
|
|
125
|
+
const cleaned = value?.trim().replace(/^CT_VAR_/, "");
|
|
126
|
+
if (!cleaned) return "input";
|
|
127
|
+
return cleaned.toLowerCase().replace(/_+/g, "-");
|
|
128
|
+
}
|
|
129
|
+
function inferFieldToken(rawField, fieldLabel, selectorTarget) {
|
|
130
|
+
const suffix = fieldNameToEnvSuffix(rawField) ?? fieldNameToEnvSuffix(fieldLabel) ?? selectorTargetToEnvSuffix(selectorTarget);
|
|
131
|
+
return placeholderTokenFromSuffix(suffix);
|
|
132
|
+
}
|
|
133
|
+
function buildFillPlaceholder(rawField, fieldLabel, selectorTarget) {
|
|
134
|
+
return `test-${inferFieldToken(rawField, fieldLabel, selectorTarget)}`;
|
|
135
|
+
}
|
|
136
|
+
function resolveLiteralFillValue(binding, selectorTarget) {
|
|
137
|
+
const rawValue = binding.value?.trim();
|
|
138
|
+
if (rawValue && !isGenericFallbackValue(rawValue) && !extractCtVarTemplate(rawValue)) {
|
|
139
|
+
return rawValue;
|
|
140
|
+
}
|
|
141
|
+
return buildFillPlaceholder(binding.rawField, binding.fieldLabel, selectorTarget);
|
|
142
|
+
}
|
|
143
|
+
function exampleValueForEnvKey(envKey) {
|
|
144
|
+
return `your-${placeholderTokenFromSuffix(envKey)}`;
|
|
145
|
+
}
|
|
120
146
|
function parseStepBinding(step) {
|
|
121
147
|
const s = step.trim();
|
|
122
148
|
const fillMatch = s.match(/\b(?:fill|input|write)\s+(?:in\s+)?(.+?)\s+with\s+(['"])(.*?)\2/i);
|
|
@@ -184,6 +210,7 @@ function resolveStepVarOverride(overrides, envKey, keySuffix, rawField, fieldLab
|
|
|
184
210
|
function extractStepVars(steps, stepHints, assertionHints, overrides) {
|
|
185
211
|
const declarations = [];
|
|
186
212
|
const byStepIndex = /* @__PURE__ */ new Map();
|
|
213
|
+
const fillValueBySelector = /* @__PURE__ */ new Map();
|
|
187
214
|
const seen = /* @__PURE__ */ new Map();
|
|
188
215
|
let unnamedFillIndex = 0;
|
|
189
216
|
let unnamedSelectIndex = 0;
|
|
@@ -198,14 +225,18 @@ function extractStepVars(steps, stepHints, assertionHints, overrides) {
|
|
|
198
225
|
for (const [index, step] of steps.entries()) {
|
|
199
226
|
const binding = parseStepBinding(step);
|
|
200
227
|
if (!binding) continue;
|
|
201
|
-
const keySuffix = fieldNameToEnvSuffix(binding.rawField) ?? fieldNameToEnvSuffix(binding.fieldLabel) ?? selectorTargetToEnvSuffix(stepHints?.[index]?.selector) ?? `${binding.kind === "select" ? "SELECT" : "INPUT"}_${binding.kind === "select" ? ++unnamedSelectIndex : ++unnamedFillIndex}`;
|
|
202
|
-
const envKey = `CT_VAR_${keySuffix}`;
|
|
203
228
|
const selectorTarget = normalizeSelectorTarget(stepHints?.[index]?.selector);
|
|
229
|
+
const keySuffix = fieldNameToEnvSuffix(binding.rawField) ?? fieldNameToEnvSuffix(binding.fieldLabel) ?? selectorTargetToEnvSuffix(selectorTarget) ?? `${binding.kind === "select" ? "SELECT" : "INPUT"}_${binding.kind === "select" ? ++unnamedSelectIndex : ++unnamedFillIndex}`;
|
|
230
|
+
const templateEnvKey = extractCtVarTemplate(binding.value);
|
|
231
|
+
const envKey = templateEnvKey ?? `CT_VAR_${keySuffix}`;
|
|
204
232
|
const assertionFallback = (selectorTarget ? assertionFallbacks.get(selectorTarget) : void 0) ?? assertionFallbacks.get(envKey);
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
233
|
+
const overrideValue = resolveStepVarOverride(overrides, envKey, keySuffix, binding.rawField, binding.fieldLabel);
|
|
234
|
+
const fallbackFromBinding = binding.value?.trim();
|
|
235
|
+
const hasRuntimeEnvValue = process.env[envKey] !== void 0;
|
|
236
|
+
const shouldDeclareVariable = binding.kind === "select" || templateEnvKey !== void 0 || overrideValue !== void 0 || hasRuntimeEnvValue;
|
|
237
|
+
let stepVar = shouldDeclareVariable ? seen.get(envKey) : void 0;
|
|
238
|
+
if (shouldDeclareVariable && !stepVar) {
|
|
239
|
+
const fallback = overrideValue ?? process.env[envKey] ?? ((!fallbackFromBinding || isGenericFallbackValue(fallbackFromBinding) || templateEnvKey) && assertionFallback ? assertionFallback : fallbackFromBinding) ?? (binding.kind === "fill" ? buildFillPlaceholder(binding.rawField, binding.fieldLabel, selectorTarget) : assertionFallback ?? "option");
|
|
209
240
|
stepVar = {
|
|
210
241
|
envKey,
|
|
211
242
|
constName: envKey,
|
|
@@ -217,22 +248,26 @@ function extractStepVars(steps, stepHints, assertionHints, overrides) {
|
|
|
217
248
|
seen.set(envKey, stepVar);
|
|
218
249
|
declarations.push(stepVar);
|
|
219
250
|
}
|
|
220
|
-
byStepIndex.set(index, stepVar);
|
|
251
|
+
if (stepVar) byStepIndex.set(index, stepVar);
|
|
252
|
+
if (binding.kind === "fill" && selectorTarget) {
|
|
253
|
+
const expression = stepVar ? stepVar.constName : `'${escapeForSingleQuotedString(resolveLiteralFillValue(binding, selectorTarget))}'`;
|
|
254
|
+
fillValueBySelector.set(selectorTarget, expression);
|
|
255
|
+
}
|
|
221
256
|
}
|
|
222
|
-
return { declarations, byStepIndex };
|
|
257
|
+
return { declarations, byStepIndex, fillValueBySelector };
|
|
223
258
|
}
|
|
224
259
|
function buildVariableHeaderComment(stepVars) {
|
|
225
260
|
if (stepVars.length === 0) return "";
|
|
226
|
-
const
|
|
261
|
+
const exampleEntries = stepVars.map((stepVar) => `${stepVar.envKey}=${exampleValueForEnvKey(stepVar.envKey)}`);
|
|
227
262
|
return [
|
|
228
|
-
"// Test variables
|
|
229
|
-
"// Set these environment variables before running
|
|
263
|
+
"// \u2500\u2500 Test variables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
264
|
+
"// Set these environment variables before running:",
|
|
230
265
|
"//",
|
|
231
|
-
...stepVars.map((stepVar) => `// ${stepVar.envKey}
|
|
266
|
+
...stepVars.map((stepVar) => `// ${stepVar.envKey}=${exampleValueForEnvKey(stepVar.envKey)}`),
|
|
232
267
|
"//",
|
|
233
268
|
"// Or pass them inline:",
|
|
234
|
-
`// ${
|
|
235
|
-
""
|
|
269
|
+
`// ${exampleEntries.join(" ")} npx playwright test`,
|
|
270
|
+
"// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
|
|
236
271
|
].join("\n");
|
|
237
272
|
}
|
|
238
273
|
function buildVariableDeclarations(stepVars) {
|
|
@@ -281,25 +316,22 @@ function parseValueAssertionHint(playwright) {
|
|
|
281
316
|
expected: parseQuotedLiteral(match[2])
|
|
282
317
|
};
|
|
283
318
|
}
|
|
284
|
-
function
|
|
319
|
+
function findFillValueExpressionForTarget(target, stepState) {
|
|
285
320
|
const normalizedTarget = normalizeSelectorTarget(target);
|
|
286
321
|
if (!normalizedTarget) return void 0;
|
|
287
|
-
|
|
288
|
-
if (bySelector) return bySelector;
|
|
289
|
-
const envSuffix = selectorTargetToEnvSuffix(normalizedTarget);
|
|
290
|
-
if (!envSuffix) return void 0;
|
|
291
|
-
return stepVars.declarations.find((stepVar) => stepVar.envKey === `CT_VAR_${envSuffix}`);
|
|
322
|
+
return stepState.fillValueBySelector.get(normalizedTarget);
|
|
292
323
|
}
|
|
293
|
-
function rewriteValueAssertionToUseVariable(playwright,
|
|
324
|
+
function rewriteValueAssertionToUseVariable(playwright, stepState) {
|
|
294
325
|
const parsed = parseValueAssertionHint(playwright);
|
|
295
326
|
if (!parsed?.target) return void 0;
|
|
296
|
-
const
|
|
297
|
-
if (!
|
|
298
|
-
return ensureStatement(`await expect(page.${parsed.target}).toHaveValue(${
|
|
327
|
+
const valueExpression = findFillValueExpressionForTarget(parsed.target, stepState);
|
|
328
|
+
if (!valueExpression) return void 0;
|
|
329
|
+
return ensureStatement(`await expect(page.${parsed.target}).toHaveValue(${valueExpression})`);
|
|
299
330
|
}
|
|
300
331
|
function stepToPlaywright(step, url, hint, stepVar) {
|
|
301
332
|
const s = step.trim();
|
|
302
333
|
const hintedSelector = hint?.selector ? `page.${hint.selector}` : void 0;
|
|
334
|
+
const selectorTarget = normalizeSelectorTarget(hint?.selector);
|
|
303
335
|
const valueExpression = (value) => stepVar?.constName ?? `'${escapeForSingleQuotedString(value)}'`;
|
|
304
336
|
if (/^(navigate|go to|open|visit|load)/i.test(s)) {
|
|
305
337
|
const urlMatch = s.match(/https?:\/\/[^\s'"]+/) || s.match(/["']([^"']+)["']/);
|
|
@@ -311,7 +343,7 @@ function stepToPlaywright(step, url, hint, stepVar) {
|
|
|
311
343
|
}
|
|
312
344
|
const binding = parseStepBinding(s);
|
|
313
345
|
if (binding?.kind === "fill") {
|
|
314
|
-
const fallbackValue =
|
|
346
|
+
const fallbackValue = stepVar?.fallback ?? resolveLiteralFillValue(binding, selectorTarget);
|
|
315
347
|
if (hintedSelector) return `await ${hintedSelector}.fill(${valueExpression(fallbackValue)});`;
|
|
316
348
|
const field = binding.fieldLabel ?? "field";
|
|
317
349
|
return `await page.getByLabel('${escapeForSingleQuotedString(field)}').fill(${valueExpression(fallbackValue)});`;
|
|
@@ -374,9 +406,9 @@ function stepToPlaywright(step, url, hint, stepVar) {
|
|
|
374
406
|
}
|
|
375
407
|
return `// TODO: map to Playwright action \u2192 "${s}"`;
|
|
376
408
|
}
|
|
377
|
-
function expectedToAssertion(expected, norm, hint,
|
|
409
|
+
function expectedToAssertion(expected, norm, hint, stepState) {
|
|
378
410
|
if (hint?.playwright) {
|
|
379
|
-
const rewritten =
|
|
411
|
+
const rewritten = stepState ? rewriteValueAssertionToUseVariable(hint.playwright, stepState) : void 0;
|
|
380
412
|
return rewritten ?? ensureStatement(hint.playwright);
|
|
381
413
|
}
|
|
382
414
|
const s = expected.trim();
|
|
@@ -458,7 +490,7 @@ function expectedToAssertion(expected, norm, hint, stepVars) {
|
|
|
458
490
|
const valMatch = s.match(/["']([^"']+)["']/);
|
|
459
491
|
if (valMatch) {
|
|
460
492
|
const envSuffix = fieldNameToEnvSuffix(fieldName);
|
|
461
|
-
const stepVar = envSuffix ?
|
|
493
|
+
const stepVar = envSuffix ? stepState?.declarations.find((candidate) => candidate.envKey === `CT_VAR_${envSuffix}`) : void 0;
|
|
462
494
|
if (stepVar) return `await expect(page.getByRole('textbox').first()).toHaveValue(${stepVar.constName});`;
|
|
463
495
|
return `await expect(page.getByRole('textbox').first()).toHaveValue('${escapeForSingleQuotedString(valMatch[1])}');`;
|
|
464
496
|
}
|
|
@@ -545,11 +577,13 @@ function buildSpecFile(norm, pomClassName, pomImportPath, overrides) {
|
|
|
545
577
|
// \u26A0\uFE0F Flagged for review \u2014 steps or assertions may need manual refinement
|
|
546
578
|
` : "";
|
|
547
579
|
const variableHeader = buildVariableHeaderComment(stepVars.declarations);
|
|
580
|
+
const variableHeaderBlock = variableHeader ? `${variableHeader}
|
|
581
|
+
` : "";
|
|
548
582
|
const variableDeclarations = buildVariableDeclarations(stepVars.declarations);
|
|
549
583
|
return `import { test, expect } from '@playwright/test';
|
|
550
584
|
import { ${pomClassName} } from '${importPath}';
|
|
551
585
|
|
|
552
|
-
${
|
|
586
|
+
${variableHeaderBlock}test('${title}', async ({ page }) => {${reviewNote}
|
|
553
587
|
const pomPage = new ${pomClassName}(page);
|
|
554
588
|
|
|
555
589
|
${variableDeclarations} // \u2500\u2500 Setup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -629,4 +663,4 @@ export {
|
|
|
629
663
|
gen,
|
|
630
664
|
genCmd
|
|
631
665
|
};
|
|
632
|
-
//# sourceMappingURL=chunk-
|
|
666
|
+
//# sourceMappingURL=chunk-RG26I5FB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/gen.ts"],"sourcesContent":["import { Command } from 'commander';\nimport fg from 'fast-glob';\nimport { readFileSync, mkdirSync, writeFileSync, existsSync } from 'node:fs';\nimport { join, basename, relative, resolve } from 'node:path';\n\ntype NormalizedCase = {\n id?: string;\n title: string;\n tags?: string[];\n steps?: string[];\n step_hints?: Array<{ selector?: string }>;\n expected?: string[];\n assertion_hints?: Array<{ playwright?: string }>;\n needs_review?: boolean;\n review_reasons?: string[];\n source?: string;\n url?: string;\n};\n\ntype VarsOverrideMap = Map<string, string>;\n\ntype StepBinding = {\n kind: 'fill' | 'select';\n rawField?: string;\n fieldLabel?: string;\n value?: string;\n};\n\ntype StepVar = {\n envKey: string;\n constName: string;\n fallback: string;\n selectorHint?: string;\n selectorTarget?: string;\n fieldLabel?: string;\n};\n\ntype StepValueState = {\n declarations: StepVar[];\n byStepIndex: Map<number, StepVar>;\n fillValueBySelector: Map<string, string>;\n};\n\nfunction escapeForSingleQuotedString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nfunction escapeForRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\\\/]/g, '\\\\$&');\n}\n\nfunction normalizeUrlForComparison(value?: string): string | undefined {\n if (!value) return undefined;\n try {\n return new URL(value).toString().replace(/\\/$/, '');\n } catch {\n return value.trim().replace(/\\/$/, '');\n }\n}\n\nfunction urlPatternFromAbsoluteUrl(value?: string): string | undefined {\n if (!value) return undefined;\n try {\n const parsed = new URL(value);\n const normalizedPath = `${parsed.pathname}${parsed.search}`.replace(/\\/$/, '') || '/';\n if (normalizedPath === '/') return '\\\\/';\n return normalizedPath.replace(/^\\/+/, '').split('/').map(escapeForRegex).join('\\\\/');\n } catch {\n return undefined;\n }\n}\n\nfunction pageNameToUrlPattern(value: string): string | undefined {\n const cleaned = value\n .replace(/\\b(the|a|an|user)\\b/gi, ' ')\n .replace(/\\b(page|screen)\\b/gi, ' ')\n .trim();\n const tokens = cleaned.split(/[\\s/-]+/).map(token => token.trim()).filter(Boolean);\n if (tokens.length === 0) return undefined;\n return tokens.map(token => escapeForRegex(token.toLowerCase())).join('[-_\\\\/]?');\n}\n\nfunction fieldNameFromSentence(value: string): string | undefined {\n const match =\n value.match(/\\bfor\\s+([a-zA-Z][a-zA-Z\\s-]{0,30}?)\\s+field\\b/i) ??\n value.match(/\\b([a-zA-Z][a-zA-Z\\s-]{0,30}?)\\s+field\\b/i) ??\n value.match(/\\b([a-zA-Z][a-zA-Z\\s-]{0,30}?)\\s+input\\b/i);\n return match?.[1]?.trim();\n}\n\nfunction visibleTextRegexFromPhrase(value: string): string {\n const cleaned = value\n .replace(/[\"']/g, '')\n .replace(/\\b(the|a|an|user|should|must|is|are|be|visible|shown|showing|displayed|present|appears?|rendered)\\b/gi, ' ')\n .replace(/\\b(message|text|content|heading|label)\\b/gi, ' ')\n .trim();\n const tokens = cleaned.split(/\\s+/).filter(Boolean);\n if (tokens.length === 0) return '.+';\n return tokens.map(token => escapeForRegex(token)).join('\\\\s+');\n}\n\nfunction sanitizeEnvSegment(value: string): string {\n return value\n .toUpperCase()\n .replace(/[^A-Z0-9]+/g, '_')\n .replace(/_+/g, '_')\n .replace(/^_|_$/g, '');\n}\n\nfunction normalizeOverrideKey(value: string): string {\n return sanitizeEnvSegment(value.replace(/^CT_VAR_/i, ''));\n}\n\nfunction cleanFieldLabel(value?: string): string | undefined {\n if (!value) return undefined;\n const cleaned = value\n .replace(/[.?!,:;]+$/g, '')\n .replace(/^(?:the|a|an)\\s+/i, '')\n .replace(/\\s+(?:field|input|box|area|dropdown|combobox|select|menu)\\b/gi, '')\n .trim();\n return cleaned || undefined;\n}\n\nfunction isPositionalFieldReference(value?: string): boolean {\n if (!value) return false;\n const cleaned = value.trim().toLowerCase();\n return /^(?:(?:the|a|an)\\s+)?(?:first|second|third|fourth|fifth|sixth|seventh|eighth|ninth|tenth|\\d+(?:st|nd|rd|th)?)(?:\\s+\\w+){0,2}\\s+(?:field|input|box|area|dropdown|combobox|select|menu)$/.test(cleaned);\n}\n\nfunction fieldNameToEnvSuffix(value?: string): string | undefined {\n if (!value || isPositionalFieldReference(value)) return undefined;\n const cleaned = value\n .replace(/[.?!,:;]+$/g, '')\n .replace(/^(?:the|a|an)\\s+/i, '')\n .replace(/\\b(?:field|input|box|area|dropdown|combobox|select|menu)\\b/gi, ' ')\n .trim();\n const suffix = sanitizeEnvSegment(cleaned);\n if (!suffix) return undefined;\n if (/^(?:FIELD|INPUT|BOX|AREA|DROPDOWN|COMBOBOX|SELECT|MENU)$/.test(suffix)) return undefined;\n return suffix;\n}\n\nfunction normalizeSelectorTarget(value?: string): string | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n return trimmed.replace(/^page\\./, '').replace(/\\s+/g, ' ');\n}\n\nfunction parseQuotedLiteral(value?: string): string | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (trimmed.length < 2) return undefined;\n\n if (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n try {\n return JSON.parse(trimmed);\n } catch {\n return trimmed.slice(1, -1);\n }\n }\n\n if (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")) {\n return trimmed\n .slice(1, -1)\n .replace(/\\\\\\\\/g, '\\\\')\n .replace(/\\\\'/g, \"'\");\n }\n\n return undefined;\n}\n\nfunction selectorTargetToEnvSuffix(value?: string): string | undefined {\n const selector = normalizeSelectorTarget(value);\n if (!selector) return undefined;\n\n const quotedArg = (pattern: RegExp, group = 2): string | undefined => {\n const match = selector.match(pattern);\n return match?.[group]?.trim();\n };\n\n const locatorArg = quotedArg(/^(?:locator)\\((['\"])(.*?)\\1\\)/i);\n if (locatorArg) {\n const idMatch = locatorArg.match(/#([A-Za-z][\\w-]*)/);\n if (idMatch) return sanitizeEnvSegment(idMatch[1]);\n\n const attrMatch = locatorArg.match(/\\[(?:name|id|data-testid|aria-label)=['\"]?([^'\"\\]]+)['\"]?\\]/i);\n if (attrMatch) return sanitizeEnvSegment(attrMatch[1]);\n\n const classMatch = locatorArg.match(/\\.([A-Za-z][\\w-]*)/);\n if (classMatch) return sanitizeEnvSegment(classMatch[1]);\n\n return sanitizeEnvSegment(locatorArg.replace(/^[#.]+/, ''));\n }\n\n const labelArg =\n quotedArg(/^(?:getByLabel|getByPlaceholder|getByTestId|getByText)\\((['\"])(.*?)\\1/i) ??\n quotedArg(/^getByRole\\((['\"])(?:textbox|searchbox|combobox|spinbutton)\\1,\\s*\\{\\s*name:\\s*(['\"])(.*?)\\2/i, 3);\n if (labelArg) return fieldNameToEnvSuffix(labelArg) ?? sanitizeEnvSegment(labelArg);\n\n return undefined;\n}\n\nfunction isGenericFallbackValue(value?: string): boolean {\n if (!value) return true;\n return /^(?:value|text|input|option|selection|selected value|default)$/i.test(value.trim());\n}\n\nfunction extractCtVarTemplate(value?: string): string | undefined {\n const match = value?.trim().match(/^\\$\\{(CT_VAR_[A-Z0-9_]+)\\}$/);\n return match?.[1];\n}\n\nfunction placeholderTokenFromSuffix(value?: string): string {\n const cleaned = value?.trim().replace(/^CT_VAR_/, '');\n if (!cleaned) return 'input';\n return cleaned.toLowerCase().replace(/_+/g, '-');\n}\n\nfunction inferFieldToken(rawField?: string, fieldLabel?: string, selectorTarget?: string): string {\n const suffix =\n fieldNameToEnvSuffix(rawField) ??\n fieldNameToEnvSuffix(fieldLabel) ??\n selectorTargetToEnvSuffix(selectorTarget);\n return placeholderTokenFromSuffix(suffix);\n}\n\nfunction buildFillPlaceholder(\n rawField?: string,\n fieldLabel?: string,\n selectorTarget?: string,\n): string {\n return `test-${inferFieldToken(rawField, fieldLabel, selectorTarget)}`;\n}\n\nfunction resolveLiteralFillValue(binding: StepBinding, selectorTarget?: string): string {\n const rawValue = binding.value?.trim();\n if (rawValue && !isGenericFallbackValue(rawValue) && !extractCtVarTemplate(rawValue)) {\n return rawValue;\n }\n return buildFillPlaceholder(binding.rawField, binding.fieldLabel, selectorTarget);\n}\n\nfunction exampleValueForEnvKey(envKey: string): string {\n return `your-${placeholderTokenFromSuffix(envKey)}`;\n}\n\nfunction parseStepBinding(step: string): StepBinding | undefined {\n const s = step.trim();\n\n const fillMatch = s.match(/\\b(?:fill|input|write)\\s+(?:in\\s+)?(.+?)\\s+with\\s+(['\"])(.*?)\\2/i);\n if (fillMatch) {\n return {\n kind: 'fill',\n rawField: fillMatch[1].trim(),\n fieldLabel: cleanFieldLabel(fillMatch[1]),\n value: fillMatch[3].trim(),\n };\n }\n\n const fillWithoutValueMatch = s.match(/\\b(?:fill|input|write)\\s+(?:in\\s+)?(.+?)$/i);\n if (fillWithoutValueMatch) {\n return {\n kind: 'fill',\n rawField: fillWithoutValueMatch[1].trim(),\n fieldLabel: cleanFieldLabel(fillWithoutValueMatch[1]),\n };\n }\n\n const enterMatch = s.match(/\\b(?:enter|type)\\s+(['\"])(.*?)\\1\\s+(?:in|into)\\s+(.+)/i);\n if (enterMatch) {\n return {\n kind: 'fill',\n rawField: enterMatch[3].trim(),\n fieldLabel: cleanFieldLabel(enterMatch[3]),\n value: enterMatch[2].trim(),\n };\n }\n\n const enterWithoutValueMatch = s.match(/\\b(?:enter|type)\\s+(?:in|into)\\s+(.+)/i);\n if (enterWithoutValueMatch) {\n return {\n kind: 'fill',\n rawField: enterWithoutValueMatch[1].trim(),\n fieldLabel: cleanFieldLabel(enterWithoutValueMatch[1]),\n };\n }\n\n const selectMatch = s.match(/\\b(?:select|choose|pick)\\s+(['\"])(.*?)\\1\\s+(?:from|in|into|on)\\s+(.+)/i);\n if (selectMatch) {\n return {\n kind: 'select',\n rawField: selectMatch[3].trim(),\n fieldLabel: cleanFieldLabel(selectMatch[3]),\n value: selectMatch[2].trim(),\n };\n }\n\n const selectWithoutValueMatch = s.match(/\\b(?:select|choose|pick)\\s+(.+?)\\s+(?:dropdown|combobox|select|menu)\\b/i);\n if (selectWithoutValueMatch) {\n return {\n kind: 'select',\n rawField: selectWithoutValueMatch[1].trim(),\n fieldLabel: cleanFieldLabel(selectWithoutValueMatch[1]),\n };\n }\n\n return undefined;\n}\n\nfunction resolveStepVarOverride(\n overrides: VarsOverrideMap,\n envKey: string,\n keySuffix: string,\n rawField?: string,\n fieldLabel?: string,\n): string | undefined {\n const candidates = [envKey, keySuffix, rawField, fieldLabel];\n for (const candidate of candidates) {\n if (!candidate) continue;\n const normalized = normalizeOverrideKey(candidate);\n if (normalized && overrides.has(normalized)) return overrides.get(normalized);\n }\n return undefined;\n}\n\nfunction extractStepVars(\n steps: string[],\n stepHints: Array<{ selector?: string }> | undefined,\n assertionHints: Array<{ playwright?: string }> | undefined,\n overrides: VarsOverrideMap,\n): StepValueState {\n const declarations: StepVar[] = [];\n const byStepIndex = new Map<number, StepVar>();\n const fillValueBySelector = new Map<string, string>();\n const seen = new Map<string, StepVar>();\n let unnamedFillIndex = 0;\n let unnamedSelectIndex = 0;\n\n const assertionFallbacks = new Map<string, string>();\n for (const hint of assertionHints ?? []) {\n const parsed = parseValueAssertionHint(hint?.playwright);\n if (!parsed?.expected) continue;\n if (parsed.target) assertionFallbacks.set(parsed.target, parsed.expected);\n const envSuffix = selectorTargetToEnvSuffix(parsed.target);\n if (envSuffix) assertionFallbacks.set(`CT_VAR_${envSuffix}`, parsed.expected);\n }\n\n for (const [index, step] of steps.entries()) {\n const binding = parseStepBinding(step);\n if (!binding) continue;\n\n const selectorTarget = normalizeSelectorTarget(stepHints?.[index]?.selector);\n const keySuffix =\n fieldNameToEnvSuffix(binding.rawField) ??\n fieldNameToEnvSuffix(binding.fieldLabel) ??\n selectorTargetToEnvSuffix(selectorTarget) ??\n `${binding.kind === 'select' ? 'SELECT' : 'INPUT'}_${binding.kind === 'select' ? ++unnamedSelectIndex : ++unnamedFillIndex}`;\n const templateEnvKey = extractCtVarTemplate(binding.value);\n const envKey = templateEnvKey ?? `CT_VAR_${keySuffix}`;\n const assertionFallback =\n (selectorTarget ? assertionFallbacks.get(selectorTarget) : undefined) ??\n assertionFallbacks.get(envKey);\n const overrideValue = resolveStepVarOverride(overrides, envKey, keySuffix, binding.rawField, binding.fieldLabel);\n const fallbackFromBinding = binding.value?.trim();\n const hasRuntimeEnvValue = process.env[envKey] !== undefined;\n const shouldDeclareVariable =\n binding.kind === 'select' ||\n templateEnvKey !== undefined ||\n overrideValue !== undefined ||\n hasRuntimeEnvValue;\n\n let stepVar = shouldDeclareVariable ? seen.get(envKey) : undefined;\n if (shouldDeclareVariable && !stepVar) {\n const fallback =\n overrideValue ??\n process.env[envKey] ??\n ((!fallbackFromBinding || isGenericFallbackValue(fallbackFromBinding) || templateEnvKey) && assertionFallback\n ? assertionFallback\n : fallbackFromBinding) ??\n (binding.kind === 'fill'\n ? buildFillPlaceholder(binding.rawField, binding.fieldLabel, selectorTarget)\n : assertionFallback ?? 'option');\n\n stepVar = {\n envKey,\n constName: envKey,\n fallback,\n selectorHint: stepHints?.[index]?.selector,\n selectorTarget,\n fieldLabel: binding.fieldLabel,\n };\n seen.set(envKey, stepVar);\n declarations.push(stepVar);\n }\n\n if (stepVar) byStepIndex.set(index, stepVar);\n if (binding.kind === 'fill' && selectorTarget) {\n const expression = stepVar\n ? stepVar.constName\n : `'${escapeForSingleQuotedString(resolveLiteralFillValue(binding, selectorTarget))}'`;\n fillValueBySelector.set(selectorTarget, expression);\n }\n }\n\n return { declarations, byStepIndex, fillValueBySelector };\n}\n\nfunction buildVariableHeaderComment(stepVars: StepVar[]): string {\n if (stepVars.length === 0) return '';\n const exampleEntries = stepVars.map((stepVar) => `${stepVar.envKey}=${exampleValueForEnvKey(stepVar.envKey)}`);\n return [\n '// ── Test variables ────────────────────────────────────────────────────────────',\n '// Set these environment variables before running:',\n '//',\n ...stepVars.map((stepVar) => `// ${stepVar.envKey}=${exampleValueForEnvKey(stepVar.envKey)}`),\n '//',\n '// Or pass them inline:',\n `// ${exampleEntries.join(' ')} npx playwright test`,\n '// ─────────────────────────────────────────────────────────────────────────────',\n ].join('\\n');\n}\n\nfunction buildVariableDeclarations(stepVars: StepVar[]): string {\n if (stepVars.length === 0) return '';\n return [\n ' // Test variables',\n ...stepVars.map(\n stepVar =>\n ` const ${stepVar.constName} = process.env['${stepVar.envKey}'] ?? '${escapeForSingleQuotedString(stepVar.fallback)}';`,\n ),\n '',\n ].join('\\n');\n}\n\nfunction parseVarsOverride(raw?: string): VarsOverrideMap {\n if (!raw) return new Map();\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n console.error('❌ --vars must be a valid JSON object');\n process.exit(1);\n }\n\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n console.error('❌ --vars must be a valid JSON object');\n process.exit(1);\n }\n\n const overrides = new Map<string, string>();\n for (const [key, value] of Object.entries(parsed)) {\n const normalizedKey = normalizeOverrideKey(key);\n if (!normalizedKey) continue;\n overrides.set(normalizedKey, String(value));\n }\n return overrides;\n}\n\n// ─── Step → Playwright action ─────────────────────────────────────────────────\n\nfunction ensureStatement(value: string): string {\n const trimmed = value.trim();\n if (!trimmed) return trimmed;\n return trimmed.endsWith(';') ? trimmed : `${trimmed};`;\n}\n\nfunction parseValueAssertionHint(playwright?: string): { target?: string; expected?: string } | undefined {\n const statement = ensureStatement(String(playwright ?? '').trim());\n if (!statement) return undefined;\n\n const match = statement.match(/expect\\(([\\s\\S]+)\\)\\.toHaveValue\\(([\\s\\S]+)\\)\\s*;$/);\n if (!match) return undefined;\n\n return {\n target: normalizeSelectorTarget(match[1]),\n expected: parseQuotedLiteral(match[2]),\n };\n}\n\nfunction findFillValueExpressionForTarget(\n target: string | undefined,\n stepState: StepValueState,\n): string | undefined {\n const normalizedTarget = normalizeSelectorTarget(target);\n if (!normalizedTarget) return undefined;\n\n return stepState.fillValueBySelector.get(normalizedTarget);\n}\n\nfunction rewriteValueAssertionToUseVariable(\n playwright: string,\n stepState: StepValueState,\n): string | undefined {\n const parsed = parseValueAssertionHint(playwright);\n if (!parsed?.target) return undefined;\n\n const valueExpression = findFillValueExpressionForTarget(parsed.target, stepState);\n if (!valueExpression) return undefined;\n\n return ensureStatement(`await expect(page.${parsed.target}).toHaveValue(${valueExpression})`);\n}\n\nfunction stepToPlaywright(\n step: string,\n url?: string,\n hint?: { selector?: string },\n stepVar?: StepVar,\n): string {\n const s = step.trim();\n const hintedSelector = hint?.selector ? `page.${hint.selector}` : undefined;\n const selectorTarget = normalizeSelectorTarget(hint?.selector);\n const valueExpression = (value: string): string =>\n stepVar?.constName ?? `'${escapeForSingleQuotedString(value)}'`;\n\n // Navigate\n if (/^(navigate|go to|open|visit|load)/i.test(s)) {\n const urlMatch = s.match(/https?:\\/\\/[^\\s'\"]+/) || s.match(/[\"']([^\"']+)[\"']/);\n const dest = urlMatch?.[1] ?? urlMatch?.[0] ?? url ?? '/';\n if (\n normalizeUrlForComparison(dest) &&\n normalizeUrlForComparison(dest) === normalizeUrlForComparison(url)\n ) {\n return `// navigation handled by pomPage.goto()`;\n }\n return `await page.goto('${escapeForSingleQuotedString(dest)}');`;\n }\n\n // Fill / type / enter into a field\n // Pattern: \"Fill in <field> with '<value>'\" or \"Enter '<value>' in <field>\"\n const binding = parseStepBinding(s);\n if (binding?.kind === 'fill') {\n const fallbackValue = stepVar?.fallback ?? resolveLiteralFillValue(binding, selectorTarget);\n if (hintedSelector) return `await ${hintedSelector}.fill(${valueExpression(fallbackValue)});`;\n const field = binding.fieldLabel ?? 'field';\n return `await page.getByLabel('${escapeForSingleQuotedString(field)}').fill(${valueExpression(fallbackValue)});`;\n }\n\n // Click a button\n if (/\\bclick\\b.*(button|btn|submit|sign in|log in|login|register|continue|next|save|confirm)/i.test(s)) {\n if (hintedSelector) return `await ${hintedSelector}.click();`;\n const nameMatch = s.match(/[\"']([^\"']+)[\"']/);\n const name = nameMatch?.[1] ?? s.replace(/click\\s+(the\\s+)?/i, '').trim();\n return `await page.getByRole('button', { name: '${escapeForSingleQuotedString(name)}' }).click();`;\n }\n\n // Click a link\n if (/\\bclick\\b.*(link|anchor|nav)/i.test(s)) {\n if (hintedSelector) return `await ${hintedSelector}.click();`;\n const nameMatch = s.match(/[\"']([^\"']+)[\"']/);\n const name = nameMatch?.[1] ?? s.replace(/click\\s+(the\\s+)?/i, '').trim();\n return `await page.getByRole('link', { name: '${escapeForSingleQuotedString(name)}' }).click();`;\n }\n\n // Generic click\n if (/^(click|press|tap)\\b/i.test(s)) {\n if (hintedSelector) return `await ${hintedSelector}.click();`;\n const nameMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (nameMatch) return `await page.getByText('${escapeForSingleQuotedString(nameMatch[1])}').click();`;\n const target = s.replace(/^(click|press|tap)\\s+(on\\s+)?/i, '').trim();\n return `await page.getByText('${escapeForSingleQuotedString(target)}').click();`;\n }\n\n // Select dropdown\n if (binding?.kind === 'select') {\n const fallbackValue = binding.value ?? stepVar?.fallback ?? 'option';\n if (hintedSelector) return `await ${hintedSelector}.selectOption(${valueExpression(fallbackValue)});`;\n if (binding.fieldLabel) {\n return `await page.getByLabel('${escapeForSingleQuotedString(binding.fieldLabel)}').selectOption(${valueExpression(fallbackValue)});`;\n }\n return `await page.getByRole('combobox').selectOption(${valueExpression(fallbackValue)});`;\n }\n\n // Check / uncheck\n if (/\\b(uncheck|untick|disable)\\b/i.test(s)) {\n if (hintedSelector) return `await ${hintedSelector}.uncheck();`;\n const nameMatch = s.match(/[\"']([^\"']+)[\"']/);\n const name = nameMatch?.[1] ?? s.replace(/uncheck|untick|disable/gi, '').trim();\n return `await page.getByLabel('${escapeForSingleQuotedString(name)}').uncheck();`;\n }\n if (/\\b(check|tick|enable)\\b/i.test(s)) {\n if (hintedSelector) return `await ${hintedSelector}.check();`;\n const nameMatch = s.match(/[\"']([^\"']+)[\"']/);\n const name = nameMatch?.[1] ?? s.replace(/check|tick|enable/gi, '').trim();\n return `await page.getByLabel('${escapeForSingleQuotedString(name)}').check();`;\n }\n\n // Keyboard key\n if (/press.*(enter|tab|escape|esc|space|backspace)/i.test(s)) {\n const keyMatch = s.match(/enter|tab|escape|esc|space|backspace/i);\n const key = (keyMatch?.[0] ?? 'Enter');\n return `await page.keyboard.press('${key.charAt(0).toUpperCase() + key.slice(1).toLowerCase()}');`;\n }\n\n // Reload\n if (/\\b(reload|refresh)\\b/i.test(s)) {\n return `await page.reload();`;\n }\n\n // Hover\n if (/\\bhover\\b/i.test(s)) {\n if (hintedSelector) return `await ${hintedSelector}.hover();`;\n const nameMatch = s.match(/[\"']([^\"']+)[\"']/);\n const name = nameMatch?.[1] ?? s.replace(/hover\\s+(over\\s+)?/i, '').trim();\n return `await page.getByText('${escapeForSingleQuotedString(name)}').hover();`;\n }\n\n // Scroll\n if (/\\bscroll\\b/i.test(s)) {\n return `await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));`;\n }\n\n // Fallback — preserve the step as a comment so the file is still valid\n return `// TODO: map to Playwright action → \"${s}\"`;\n}\n\n// ─── Expected result → assertion ──────────────────────────────────────────────\n\nfunction expectedToAssertion(\n expected: string,\n norm?: NormalizedCase,\n hint?: { playwright?: string },\n stepState?: StepValueState,\n): string {\n if (hint?.playwright) {\n const rewritten = stepState ? rewriteValueAssertionToUseVariable(hint.playwright, stepState) : undefined;\n return rewritten ?? ensureStatement(hint.playwright);\n }\n const s = expected.trim();\n const fieldName = fieldNameFromSentence(s);\n const currentUrlPattern = urlPatternFromAbsoluteUrl(norm?.url);\n\n // Cleared / empty field\n if (/\\b(clear|cleared|empty|blank)\\b/i.test(s) && /\\b(field|input|value)\\b/i.test(s) && fieldName) {\n return `await expect(page.getByLabel('${escapeForSingleQuotedString(fieldName)}')).toHaveValue('');`;\n }\n\n // Stayed on the same page / did not submit\n if (/\\bform\\b.*\\b(?:does not submit|doesn't submit|not submit|not submitted)\\b/i.test(s)) {\n const fallbackPattern = currentUrlPattern || 'login';\n return `await expect(page).toHaveURL(/${fallbackPattern}/); // form did not navigate`;\n }\n if (/\\b(remains?|stays?|still)\\s+on\\b/i.test(s)) {\n const pageMatch = s.match(/\\b(?:remains?|stays?|still)\\s+on\\s+(?:the\\s+)?(.+?)(?:\\s+page|\\s+screen)?$/i);\n const pagePattern = pageMatch?.[1] ? pageNameToUrlPattern(pageMatch[1]) : undefined;\n return `await expect(page).toHaveURL(/${pagePattern || currentUrlPattern || 'login'}/);`;\n }\n\n // URL / redirect check\n if (/\\b(url|redirect(?:s|ed)?|navigate(?:s|d)?|route|path)\\b/i.test(s)) {\n const pathMatch =\n s.match(/[\"'](\\/[^\"']+)[\"']/) ??\n s.match(/to\\s+(\\/[\\w/-]+)/i) ??\n s.match(/https?:\\/\\/[^\\s'\"]+/i);\n const matchedPath = pathMatch?.[1] ?? pathMatch?.[0];\n if (matchedPath) {\n const fromUrl = matchedPath.startsWith('http') ? urlPatternFromAbsoluteUrl(matchedPath) : undefined;\n const directPath = matchedPath.startsWith('/') ? matchedPath.replace(/^\\/+/, '').split('/').map(escapeForRegex).join('\\\\/') : undefined;\n const finalPattern = fromUrl ?? directPath ?? currentUrlPattern;\n if (finalPattern !== undefined) return `await expect(page).toHaveURL(/${finalPattern}/);`;\n }\n return `await expect(page).toHaveURL(/dashboard|success|home/);`;\n }\n\n // Page title\n if (/\\bpage title\\b|\\btitle should\\b|\\bdocument title\\b/i.test(s)) {\n const titleMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (titleMatch) return `await expect(page).toHaveTitle('${escapeForSingleQuotedString(titleMatch[1])}');`;\n return `await expect(page).toHaveTitle(/.+/);`;\n }\n\n // Error / validation message\n if (/\\b(error|invalid|fail|incorrect|required|validation)\\b/i.test(s)) {\n const msgMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (msgMatch) return `await expect(page.getByText('${escapeForSingleQuotedString(msgMatch[1])}')).toBeVisible();`;\n if (fieldName) return `await expect(page.getByText(/${escapeForRegex(fieldName)}/i)).toBeVisible();`;\n return `await expect(page.getByRole('alert')).toBeVisible();`;\n }\n\n // Success / confirmation\n if (/\\b(success|confirm|complete|thank|welcome|sent|saved)\\b/i.test(s)) {\n const msgMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (msgMatch) return `await expect(page.getByText('${escapeForSingleQuotedString(msgMatch[1])}')).toBeVisible();`;\n if (/\\bwelcome\\b/i.test(s)) return `await expect(page.getByText(/welcome/i)).toBeVisible();`;\n return `await expect(page.getByRole('status')).toBeVisible();`;\n }\n\n // Not visible / hidden\n if (/\\b(not visible|hidden|disappear|removed|gone)\\b/i.test(s)) {\n const elementMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (elementMatch) return `await expect(page.getByText('${escapeForSingleQuotedString(elementMatch[1])}')).not.toBeVisible();`;\n return `await expect(page.locator('.modal, [role=\"dialog\"]').first()).not.toBeVisible();`;\n }\n\n // Visible / present\n if (/\\b(visible|appear|display|show|render|present)\\b/i.test(s)) {\n const elementMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (elementMatch) return `await expect(page.getByText('${escapeForSingleQuotedString(elementMatch[1])}')).toBeVisible();`;\n const subjectMatch =\n s.match(/^(?:the\\s+)?(.+?)\\s+(?:is|are|should|must|becomes?|appears?|renders?|shows?|displays?)\\b/i) ??\n s.match(/^(?:the\\s+)?(.+?)\\s+(?:visible|present)\\b/i);\n const subject = subjectMatch?.[1]?.trim();\n if (subject) {\n if (/\\bnavigation\\b.*\\bmenu\\b|\\bmenu\\b.*\\bnavigation\\b|\\bnavigation\\b/i.test(subject)) {\n return `await expect(page.getByRole('navigation')).toBeVisible();`;\n }\n return `await expect(page.getByText(/${visibleTextRegexFromPhrase(subject)}/i)).toBeVisible();`;\n }\n return `await expect(page.locator('[data-testid]').first()).toBeVisible();`;\n }\n\n // Count of items\n if (/\\b(count|number of|list of|\\d+\\s+item)\\b/i.test(s)) {\n const countMatch = s.match(/(\\d+)/);\n if (countMatch) return `await expect(page.locator('li, tr, [role=\"listitem\"]')).toHaveCount(${countMatch[1]});`;\n return `await expect(page.locator('li, tr').first()).toBeVisible();`;\n }\n\n // Enabled / disabled\n if (/\\b(enabled|clickable|active)\\b/i.test(s)) {\n return `await expect(page.getByRole('button').first()).toBeEnabled();`;\n }\n if (/\\b(disabled|inactive)\\b/i.test(s)) {\n return `await expect(page.getByRole('button').first()).toBeDisabled();`;\n }\n\n // Input value\n if (/\\b(clear|cleared|empty|blank)\\b/i.test(s) && /\\b(field|input|value)\\b/i.test(s)) {\n return `await expect(page.getByRole('textbox').first()).toHaveValue('');`;\n }\n if (/\\b(field|input|value|filled)\\b/i.test(s)) {\n const valMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (valMatch) {\n const envSuffix = fieldNameToEnvSuffix(fieldName);\n const stepVar = envSuffix ? stepState?.declarations.find(candidate => candidate.envKey === `CT_VAR_${envSuffix}`) : undefined;\n if (stepVar) return `await expect(page.getByRole('textbox').first()).toHaveValue(${stepVar.constName});`;\n return `await expect(page.getByRole('textbox').first()).toHaveValue('${escapeForSingleQuotedString(valMatch[1])}');`;\n }\n return `await expect(page.getByRole('textbox').first()).not.toBeEmpty();`;\n }\n\n // Text / heading / content (broad fallback before final fallback)\n if (/\\b(text|content|label|message|heading)\\b/i.test(s)) {\n const textMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (textMatch) return `await expect(page.getByText('${escapeForSingleQuotedString(textMatch[1])}')).toBeVisible();`;\n const words = s.replace(/\\b(the|should|must|contain|display|show|have|text|content)\\b/gi, '').trim();\n return `await expect(page.getByText(/${visibleTextRegexFromPhrase(words)}/i)).toBeVisible();`;\n }\n\n // Final fallback\n const cleaned = s.replace(/[\"']/g, '').trim();\n return `await expect(page.getByText(/${visibleTextRegexFromPhrase(cleaned)}/i)).toBeVisible(); // TODO: refine assertion`;\n}\n\n// ─── POM class name / filename ────────────────────────────────────────────────\n\nfunction toIdentifier(value: string, fallback = 'Landing'): string {\n const tokens = value\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .split(/[^a-zA-Z0-9_]+/)\n .filter(Boolean);\n\n const identifier = tokens\n .map((token) => token.charAt(0).toUpperCase() + token.slice(1))\n .join('');\n\n if (!identifier) return fallback;\n return /^[0-9]/.test(identifier) ? `Case${identifier}` : identifier;\n}\n\nfunction derivePomClassName(norm: NormalizedCase): string {\n const raw = norm.id ?? norm.title ?? 'Landing';\n const withoutNum = raw.replace(/-\\d+$/, '');\n return `${toIdentifier(withoutNum)}Page`;\n}\n\n// ─── POM class source ─────────────────────────────────────────────────────────\n\nfunction buildPomClass(className: string, norm: NormalizedCase, lang: 'ts' | 'js'): string {\n const pageUrl = norm.url ?? '/';\n const isTs = lang === 'ts';\n\n return isTs\n ? `import { Page } from '@playwright/test';\n\nexport class ${className} {\n readonly page: Page;\n\n constructor(page: Page) {\n this.page = page;\n }\n\n async goto(): Promise<void> {\n await this.page.goto('${escapeForSingleQuotedString(pageUrl)}');\n }\n\n async waitForLoad(): Promise<void> {\n await this.page.waitForLoadState('domcontentloaded');\n }\n}\n`\n : `// @ts-check\nexport class ${className} {\n /** @param {import('@playwright/test').Page} page */\n constructor(page) {\n /** @type {import('@playwright/test').Page} */\n this.page = page;\n }\n\n async goto() {\n await this.page.goto('${escapeForSingleQuotedString(pageUrl)}');\n }\n\n async waitForLoad() {\n await this.page.waitForLoadState('domcontentloaded');\n }\n}\n`;\n}\n\n// ─── Spec file source ─────────────────────────────────────────────────────────\n\nfunction buildTestTitle(norm: NormalizedCase): string {\n const idPart = norm.id ?? '';\n\n // norm.title may already include the ID prefix (e.g. \"AUTH-001 — User can log in\")\n // Strip it to avoid \"AUTH-001 — AUTH-001 — User can log in\" in the test name.\n let cleanTitle = norm.title || 'Untitled';\n if (idPart && cleanTitle.startsWith(idPart)) {\n cleanTitle = cleanTitle.slice(idPart.length).replace(/^\\s*[—\\-–]+\\s*/, '').trim();\n }\n\n const tagSuffix = (norm.tags ?? []).map(t => `@${t}`).join(' ');\n return [idPart, cleanTitle, tagSuffix].filter(Boolean).join(' — ').trim();\n}\n\nfunction buildSpecFile(\n norm: NormalizedCase,\n pomClassName: string,\n pomImportPath: string,\n overrides: VarsOverrideMap,\n): string {\n const title = buildTestTitle(norm);\n const steps = norm.steps ?? [];\n const expected = norm.expected ?? [];\n const stepVars = extractStepVars(steps, norm.step_hints, norm.assertion_hints, overrides);\n\n let importPath = pomImportPath.replace(/\\\\/g, '/');\n if (!importPath.startsWith('.')) importPath = `./${importPath}`;\n // Strip .ts extension — TypeScript resolves without it\n importPath = importPath.replace(/\\.ts$/, '');\n\n const stepLines = steps.length\n ? steps\n .map((s, index) => ` ${stepToPlaywright(s, norm.url, norm.step_hints?.[index], stepVars.byStepIndex.get(index))}`)\n .join('\\n')\n : ' // TODO: add steps';\n\n const assertionLines = expected.length\n ? expected.map((e, index) => ` ${expectedToAssertion(e, norm, norm.assertion_hints?.[index], stepVars)}`).join('\\n')\n : ' // TODO: add assertions';\n\n const reviewNote = norm.needs_review\n ? `\\n // ⚠️ Flagged for review — steps or assertions may need manual refinement\\n`\n : '';\n const variableHeader = buildVariableHeaderComment(stepVars.declarations);\n const variableHeaderBlock = variableHeader ? `${variableHeader}\\n` : '';\n const variableDeclarations = buildVariableDeclarations(stepVars.declarations);\n\n return `import { test, expect } from '@playwright/test';\nimport { ${pomClassName} } from '${importPath}';\n\n${variableHeaderBlock}test('${title}', async ({ page }) => {${reviewNote}\n const pomPage = new ${pomClassName}(page);\n\n${variableDeclarations} // ── Setup ─────────────────────────────────────────────────────────────────\n await pomPage.goto();\n await pomPage.waitForLoad();\n\n // ── Steps ─────────────────────────────────────────────────────────────────\n${stepLines}\n\n // ── Assertions ────────────────────────────────────────────────────────────\n${assertionLines}\n});\n`;\n}\n\n// ─── Main ─────────────────────────────────────────────────────────────────────\n\nexport async function gen(opts: { lang: string; out: string; vars?: string }) {\n if (opts.lang !== 'ts' && opts.lang !== 'js') {\n console.error('❌ --lang must be ts or js');\n process.exit(1);\n }\n const lang = opts.lang as 'ts' | 'js';\n const specExt = lang === 'js' ? 'spec.js' : 'spec.ts';\n const pomExt = lang === 'js' ? '.js' : '.ts';\n const varsOverride = parseVarsOverride(opts.vars);\n\n const normalized = await fg([\n '.cementic/normalized/*.json',\n '!.cementic/normalized/_index.json',\n ]);\n\n if (normalized.length === 0) {\n console.warn('⚠️ No normalized cases found in .cementic/normalized/');\n console.warn(' Run: ct normalize ./cases');\n process.exit(1);\n }\n\n const projectRoot = process.cwd();\n const testsOutDir = resolve(projectRoot, opts.out);\n const pagesOutDir = resolve(projectRoot, 'pages');\n\n mkdirSync(testsOutDir, { recursive: true });\n mkdirSync(pagesOutDir, { recursive: true });\n\n let specCount = 0;\n let pomCount = 0;\n\n for (const f of normalized) {\n const norm = JSON.parse(readFileSync(f, 'utf8')) as NormalizedCase;\n\n const pomClassName = derivePomClassName(norm);\n const pomFileName = pomClassName + pomExt;\n const pomFilePath = join(pagesOutDir, pomFileName);\n\n // Only write a POM file if one doesn't exist yet — never overwrite user edits\n if (!existsSync(pomFilePath)) {\n writeFileSync(pomFilePath, buildPomClass(pomClassName, norm, lang));\n pomCount++;\n }\n\n // Relative import from the test file location to the POM file\n const relToPages = relative(testsOutDir, pagesOutDir);\n const pomImportPath = join(relToPages, pomFileName);\n\n const stem = basename(f).replace(/\\.json$/, '').replace(/[^\\w-]+/g, '-');\n const specPath = join(testsOutDir, `${stem}.${specExt}`);\n writeFileSync(specPath, buildSpecFile(norm, pomClassName, pomImportPath, varsOverride));\n specCount++;\n }\n\n console.log(`✅ Generated ${specCount} spec file(s) → ${opts.out}/`);\n if (pomCount > 0) {\n console.log(`✅ Generated ${pomCount} POM class file(s) → pages/`);\n }\n if (pomCount === 0 && specCount > 0) {\n console.log(`ℹ️ POM classes already exist — skipped regeneration`);\n }\n}\n\nexport function genCmd() {\n const cmd = new Command('gen')\n .description('Generate Playwright POM spec + page-object files from normalized cases')\n .addHelpText('after', `\nExamples:\n $ ct gen --lang ts\n $ ct gen --lang js --out tests/e2e\n $ ct gen --lang ts --vars '{\"email\":\"admin@example.com\"}'\n`)\n .option('--lang <lang>', 'Target language (ts|js)', 'ts')\n .option('--out <dir>', 'Output directory for spec files', 'tests/generated')\n .option('--vars <json>', 'JSON object of fallback values for generated CT_VAR_* constants')\n .action(async opts => {\n await gen({ lang: opts.lang, out: opts.out, vars: opts.vars });\n });\n return cmd;\n}\n"],"mappings":"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","names":[]}
|