@cementic/cementic-test 0.2.16 → 0.2.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  All notable changes to `@cementic/cementic-test` are documented here.
4
4
 
5
+ ## v0.2.17
6
+
7
+ - fixed `ct gen` URL assertions so redirect and stay-on-page regexes are derived from the exact intent text, including `secure area -> /secure/` and `login page -> /login/`
8
+ - stripped leaked backticks from generated regex literals so negative URL assertions no longer emit invalid patterns such as ``/`[-_\/]?login`/``
9
+ - added a post-generation Playwright validation pass that repairs known method typos such as `.fil()` before files are written
10
+ - fixed negative auth generation so the field under test uses a deliberately invalid literal value instead of reusing valid `CT_VAR_*` credentials
11
+ - updated package metadata, capture artifact metadata, and capture user agent strings to `0.2.17`
12
+
5
13
  ## v0.2.16
6
14
 
7
15
  - fixed `ct gen` so unquoted and backticked step values such as ```${CT_VAR_EMAIL}``` now map to runnable `.fill()` and `.selectOption()` calls instead of falling back to `TODO` comments
package/README.md CHANGED
@@ -218,9 +218,9 @@ node --test --test-name-pattern="counting intent" test/prompt.spec.mjs
218
218
 
219
219
  Note: on current Node test runner versions, use `--test-reporter=spec`, not `--reporter=spec`.
220
220
 
221
- ### v0.2.16 acceptance criteria
221
+ ### v0.2.17 acceptance criteria
222
222
 
223
- All of the following must be true before publishing `v0.2.16`:
223
+ All of the following must be true before publishing `v0.2.17`:
224
224
 
225
225
  - `npm test` passes from a clean checkout and includes both the integration suite and `test/prompt.spec.mjs`
226
226
  - `prepublishOnly` runs the same full release gate, not just `build`
@@ -253,7 +253,11 @@ All of the following must be true before publishing `v0.2.16`:
253
253
  - no `TODO` comments for recognized fill/select auth steps using quoted, unquoted, or backticked `CT_VAR_*` values
254
254
  - env-backed `CT_VAR_*` extraction when matching vars are available
255
255
  - field-specific fallback values when env vars are not available
256
+ - redirect and stay-on-page assertions derive `toHaveURL(/.../)` from the exact intent text or explicit path instead of generic hardcoded alternates
257
+ - backticks never leak into generated regex literals
258
+ - field-specific negative auth tests use deliberately invalid literal values for the field under test
256
259
  - generic auth button click steps fall back to resilient role-name matching when exact labels are missing
260
+ - generated Playwright method calls are validated before files are written, and known typos such as `.fil()` are repaired to valid API names
257
261
  - existing POM files are not overwritten
258
262
  - generated specs compile as valid Playwright TypeScript or JavaScript
259
263
  - command smoke coverage passes for:
@@ -459,6 +463,12 @@ And start automating.
459
463
 
460
464
  See [CHANGELOG.md](./CHANGELOG.md) for the full release history.
461
465
 
466
+ ### v0.2.17
467
+
468
+ - fixed `ct gen` URL assertions so redirect and stay-on-page regexes now come from the exact intent text, including `secure area -> /secure/` and `login page -> /login/`
469
+ - stripped leaked backticks from generated regex literals and added a post-generation Playwright validation pass that repairs known typos such as `.fil()`
470
+ - fixed negative auth generation so the field under test uses a deliberately invalid literal instead of reusing valid `CT_VAR_*` credentials
471
+
462
472
  ### v0.2.16
463
473
 
464
474
  - fixed `ct gen` so unquoted and backticked `CT_VAR_*` fill steps now generate runnable `.fill()` calls instead of `TODO` comments
package/dist/capture.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  formatCaptureFailure,
7
7
  inferInteractiveRole,
8
8
  toPageSummary
9
- } from "./chunk-WUGSOKKY.js";
9
+ } from "./chunk-JWGYAQ3O.js";
10
10
  export {
11
11
  CaptureRuntimeError,
12
12
  captureElements,
@@ -30,12 +30,27 @@ function urlPatternFromAbsoluteUrl(value) {
30
30
  return void 0;
31
31
  }
32
32
  }
33
+ function sanitizeUrlIntentPhrase(value) {
34
+ return value.replace(/`+/g, " ").replace(/^\/+/, " ").replace(/\/[dgimsuvy]*$/i, " ").replace(/["']/g, " ").replace(/\b(?:the|a|an|user|same|current)\b/gi, " ").replace(/\b(?:page|screen|view|area|section|route|path|url|form)\b/gi, " ").replace(/\s+/g, " ").trim();
35
+ }
33
36
  function pageNameToUrlPattern(value) {
34
- const cleaned = value.replace(/\b(the|a|an|user)\b/gi, " ").replace(/\b(page|screen)\b/gi, " ").trim();
37
+ const cleaned = sanitizeUrlIntentPhrase(value);
35
38
  const tokens = cleaned.split(/[\s/-]+/).map((token) => token.trim()).filter(Boolean);
36
39
  if (tokens.length === 0) return void 0;
37
40
  return tokens.map((token) => escapeForRegex(token.toLowerCase())).join("[-_\\/]?");
38
41
  }
42
+ function urlPatternFromIntentText(value) {
43
+ const sanitized = value.replace(/`+/g, "").trim();
44
+ const explicitPathMatch = sanitized.match(/["'](\/[^"']+)["']/) ?? sanitized.match(/\b(?:to|on|at)\s+(\/[\w/-]+)/i) ?? sanitized.match(/https?:\/\/[^\s'"]+/i);
45
+ const explicitPath = explicitPathMatch?.[1] ?? explicitPathMatch?.[0];
46
+ if (explicitPath) {
47
+ const fromUrl = explicitPath.startsWith("http") ? urlPatternFromAbsoluteUrl(explicitPath) : void 0;
48
+ const fromPath = explicitPath.startsWith("/") ? explicitPath.replace(/^\/+/, "").split("/").map(escapeForRegex).join("\\/") : void 0;
49
+ return fromUrl ?? fromPath;
50
+ }
51
+ const phraseMatch = sanitized.match(/\b(?:redirect(?:s|ed)?|navigat(?:e|es|ed)|go(?:es|ne)?|route|path|url)\b(?:\s+(?:to|on|contains))?\s+(?:the\s+)?(.+?)(?:[.?!]|$)/i) ?? sanitized.match(/\b(?:remain|remains|stays|stay|still)\s+(?:on|at)\s+(?:the\s+)?(.+?)(?:[.?!]|$)/i);
52
+ return phraseMatch?.[1] ? pageNameToUrlPattern(phraseMatch[1]) : void 0;
53
+ }
39
54
  function fieldNameFromSentence(value) {
40
55
  const match = value.match(/\bfor\s+([a-zA-Z][a-zA-Z\s-]{0,30}?)\s+field\b/i) ?? value.match(/\b([a-zA-Z][a-zA-Z\s-]{0,30}?)\s+field\b/i) ?? value.match(/\b([a-zA-Z][a-zA-Z\s-]{0,30}?)\s+input\b/i);
41
56
  return match?.[1]?.trim();
@@ -235,6 +250,38 @@ function parseStepBinding(step) {
235
250
  }
236
251
  return void 0;
237
252
  }
253
+ function inferNegativeAuthTarget(norm) {
254
+ const tags = (norm.tags ?? []).map((tag) => tag.toLowerCase());
255
+ const content = [norm.id, norm.title, ...norm.expected ?? []].filter(Boolean).join(" ").toLowerCase();
256
+ const isNegativeCase = tags.includes("negative") || /\b(invalid|wrong|incorrect|bad|nonexistent|not an email)\b/.test(content);
257
+ if (!isNegativeCase) return void 0;
258
+ if (/\b(?:invalid|wrong|incorrect|bad|not an email)\s+(?:e-?mail|email)\b|\b(?:e-?mail|email)\b.{0,24}\b(?:invalid|wrong|incorrect|bad|not an email)\b/.test(content)) {
259
+ return "EMAIL";
260
+ }
261
+ if (/\b(?:invalid|wrong|incorrect|bad|nonexistent)\s+(?:user(?:name)?|login)\b|\b(?:user(?:name)?|login)\b.{0,24}\b(?:invalid|wrong|incorrect|bad|nonexistent)\b/.test(content)) {
262
+ return "USERNAME";
263
+ }
264
+ if (/\b(?:invalid|wrong|incorrect|bad)\s+password\b|\bpassword\b.{0,24}\b(?:invalid|wrong|incorrect|bad)\b/.test(content)) {
265
+ return "PASSWORD";
266
+ }
267
+ return void 0;
268
+ }
269
+ function negativeAuthFallbackValue(target) {
270
+ return target === "EMAIL" ? "invalid-not-an-email" : target === "PASSWORD" ? "wrong-password-123" : "nonexistent-user";
271
+ }
272
+ function rewriteNegativeAuthSteps(steps, stepHints, norm) {
273
+ const target = inferNegativeAuthTarget(norm);
274
+ if (!target) return steps;
275
+ return steps.map((step, index) => {
276
+ const binding = parseStepBinding(step);
277
+ if (binding?.kind !== "fill") return step;
278
+ const selectorTarget = normalizeSelectorTarget(stepHints?.[index]?.selector);
279
+ const fieldSuffix = fieldNameToEnvSuffix(binding.rawField) ?? fieldNameToEnvSuffix(binding.fieldLabel) ?? selectorTargetToEnvSuffix(selectorTarget);
280
+ if (fieldSuffix !== target) return step;
281
+ const rawField = binding.rawField ?? binding.fieldLabel ?? "field";
282
+ return `Fill in ${rawField} with '${negativeAuthFallbackValue(target)}'`;
283
+ });
284
+ }
238
285
  function resolveStepVarOverride(overrides, envKey, keySuffix, rawField, fieldLabel) {
239
286
  const candidates = [envKey, keySuffix, rawField, fieldLabel];
240
287
  for (const candidate of candidates) {
@@ -270,7 +317,8 @@ function extractStepVars(steps, stepHints, assertionHints, overrides) {
270
317
  const overrideValue = resolveStepVarOverride(overrides, envKey, keySuffix, binding.rawField, binding.fieldLabel);
271
318
  const fallbackFromBinding = binding.value?.trim();
272
319
  const hasRuntimeEnvValue = process.env[envKey] !== void 0;
273
- const shouldDeclareVariable = binding.kind === "select" || templateEnvKey !== void 0 || overrideValue !== void 0 || hasRuntimeEnvValue;
320
+ const shouldUseRuntimeEnvValue = hasRuntimeEnvValue && (!fallbackFromBinding || isGenericFallbackValue(fallbackFromBinding));
321
+ const shouldDeclareVariable = binding.kind === "select" || templateEnvKey !== void 0 || overrideValue !== void 0 || shouldUseRuntimeEnvValue;
274
322
  let stepVar = shouldDeclareVariable ? seen.get(envKey) : void 0;
275
323
  if (shouldDeclareVariable && !stepVar) {
276
324
  const placeholderFallback = binding.kind === "fill" ? buildFillPlaceholder(binding.rawField, binding.fieldLabel, selectorTarget) : assertionFallback ?? "option";
@@ -485,20 +533,12 @@ function expectedToAssertion(expected, norm, hint, stepState) {
485
533
  return `await expect(page).toHaveURL(/${fallbackPattern}/); // form did not navigate`;
486
534
  }
487
535
  if (/\b(remains?|stays?|still)\s+on\b/i.test(s)) {
488
- const pageMatch = s.match(/\b(?:remains?|stays?|still)\s+on\s+(?:the\s+)?(.+?)(?:\s+page|\s+screen)?$/i);
489
- const pagePattern = pageMatch?.[1] ? pageNameToUrlPattern(pageMatch[1]) : void 0;
536
+ const pagePattern = urlPatternFromIntentText(s);
490
537
  return `await expect(page).toHaveURL(/${pagePattern || currentUrlPattern || "login"}/);`;
491
538
  }
492
539
  if (/\b(url|redirect(?:s|ed)?|navigate(?:s|d)?|route|path)\b/i.test(s)) {
493
- const pathMatch = s.match(/["'](\/[^"']+)["']/) ?? s.match(/to\s+(\/[\w/-]+)/i) ?? s.match(/https?:\/\/[^\s'"]+/i);
494
- const matchedPath = pathMatch?.[1] ?? pathMatch?.[0];
495
- if (matchedPath) {
496
- const fromUrl = matchedPath.startsWith("http") ? urlPatternFromAbsoluteUrl(matchedPath) : void 0;
497
- const directPath = matchedPath.startsWith("/") ? matchedPath.replace(/^\/+/, "").split("/").map(escapeForRegex).join("\\/") : void 0;
498
- const finalPattern = fromUrl ?? directPath ?? currentUrlPattern;
499
- if (finalPattern !== void 0) return `await expect(page).toHaveURL(/${finalPattern}/);`;
500
- }
501
- return `await expect(page).toHaveURL(/dashboard|success|home/);`;
540
+ const finalPattern = urlPatternFromIntentText(s) ?? currentUrlPattern ?? ".+";
541
+ return `await expect(page).toHaveURL(/${finalPattern}/);`;
502
542
  }
503
543
  if (/\bpage title\b|\btitle should\b|\bdocument title\b/i.test(s)) {
504
544
  const titleMatch = s.match(/["']([^"']+)["']/);
@@ -631,7 +671,7 @@ function buildTestTitle(norm) {
631
671
  }
632
672
  function buildSpecFile(norm, pomClassName, pomImportPath, overrides) {
633
673
  const title = buildTestTitle(norm);
634
- const steps = norm.steps ?? [];
674
+ const steps = rewriteNegativeAuthSteps(norm.steps ?? [], norm.step_hints, norm);
635
675
  const expected = norm.expected ?? [];
636
676
  const stepVars = extractStepVars(steps, norm.step_hints, norm.assertion_hints, overrides);
637
677
  let importPath = pomImportPath.replace(/\\/g, "/");
@@ -664,6 +704,87 @@ ${assertionLines}
664
704
  });
665
705
  `;
666
706
  }
707
+ var PLAYWRIGHT_METHOD_NAMES = /* @__PURE__ */ new Set([
708
+ "all",
709
+ "check",
710
+ "click",
711
+ "evaluate",
712
+ "fill",
713
+ "filter",
714
+ "first",
715
+ "getByLabel",
716
+ "getByPlaceholder",
717
+ "getByRole",
718
+ "getByTestId",
719
+ "getByText",
720
+ "goto",
721
+ "hover",
722
+ "locator",
723
+ "nth",
724
+ "or",
725
+ "press",
726
+ "reload",
727
+ "selectOption",
728
+ "toBeChecked",
729
+ "toBeDisabled",
730
+ "toBeEnabled",
731
+ "toBeHidden",
732
+ "toBeVisible",
733
+ "toContainText",
734
+ "toHaveCount",
735
+ "toHaveTitle",
736
+ "toHaveURL",
737
+ "toHaveValue",
738
+ "uncheck",
739
+ "waitForEvent",
740
+ "waitForLoad",
741
+ "waitForLoadState"
742
+ ]);
743
+ function levenshteinDistance(left, right) {
744
+ const distances = Array.from({ length: right.length + 1 }, (_, index) => index);
745
+ for (let row = 1; row <= left.length; row++) {
746
+ let previousDiagonal = distances[0];
747
+ distances[0] = row;
748
+ for (let column = 1; column <= right.length; column++) {
749
+ const temp = distances[column];
750
+ distances[column] = Math.min(
751
+ distances[column] + 1,
752
+ distances[column - 1] + 1,
753
+ previousDiagonal + (left[row - 1] === right[column - 1] ? 0 : 1)
754
+ );
755
+ previousDiagonal = temp;
756
+ }
757
+ }
758
+ return distances[right.length];
759
+ }
760
+ function findClosestPlaywrightMethod(methodName) {
761
+ let bestCandidate;
762
+ let bestDistance = Number.POSITIVE_INFINITY;
763
+ for (const candidate of PLAYWRIGHT_METHOD_NAMES) {
764
+ if (candidate[0] !== methodName[0]) continue;
765
+ const distance = levenshteinDistance(methodName, candidate);
766
+ if (distance < bestDistance) {
767
+ bestDistance = distance;
768
+ bestCandidate = candidate;
769
+ }
770
+ }
771
+ return bestDistance <= 2 ? bestCandidate : void 0;
772
+ }
773
+ function stripBackticksInsideRegexLiterals(line) {
774
+ return line.includes("`") ? line.replace(/`/g, "") : line;
775
+ }
776
+ function repairPlaywrightMethodsInLine(line, fileLabel) {
777
+ if (!/\bawait\b/.test(line)) return line;
778
+ return line.replace(/\.(\w+)\(/g, (match, methodName) => {
779
+ if (PLAYWRIGHT_METHOD_NAMES.has(methodName)) return match;
780
+ const repaired = findClosestPlaywrightMethod(methodName);
781
+ if (repaired) return `.${repaired}(`;
782
+ throw new Error(`Generated unsupported Playwright method ".${methodName}(" in ${fileLabel}`);
783
+ });
784
+ }
785
+ function finalizeGeneratedPlaywrightSource(source, fileLabel) {
786
+ return source.split("\n").map((line) => repairPlaywrightMethodsInLine(stripBackticksInsideRegexLiterals(line), fileLabel)).join("\n");
787
+ }
667
788
  async function gen(opts) {
668
789
  if (opts.lang !== "ts" && opts.lang !== "js") {
669
790
  console.error("\u274C --lang must be ts or js");
@@ -695,14 +816,23 @@ async function gen(opts) {
695
816
  const pomFileName = pomClassName + pomExt;
696
817
  const pomFilePath = join(pagesOutDir, pomFileName);
697
818
  if (!existsSync(pomFilePath)) {
698
- writeFileSync(pomFilePath, buildPomClass(pomClassName, norm, lang));
819
+ writeFileSync(
820
+ pomFilePath,
821
+ finalizeGeneratedPlaywrightSource(buildPomClass(pomClassName, norm, lang), pomFileName)
822
+ );
699
823
  pomCount++;
700
824
  }
701
825
  const relToPages = relative(testsOutDir, pagesOutDir);
702
826
  const pomImportPath = join(relToPages, pomFileName);
703
827
  const stem = basename(f).replace(/\.json$/, "").replace(/[^\w-]+/g, "-");
704
828
  const specPath = join(testsOutDir, `${stem}.${specExt}`);
705
- writeFileSync(specPath, buildSpecFile(norm, pomClassName, pomImportPath, varsOverride));
829
+ writeFileSync(
830
+ specPath,
831
+ finalizeGeneratedPlaywrightSource(
832
+ buildSpecFile(norm, pomClassName, pomImportPath, varsOverride),
833
+ basename(specPath)
834
+ )
835
+ );
706
836
  specCount++;
707
837
  }
708
838
  console.log(`\u2705 Generated ${specCount} spec file(s) \u2192 ${opts.out}/`);
@@ -726,7 +856,8 @@ Examples:
726
856
  }
727
857
 
728
858
  export {
859
+ finalizeGeneratedPlaywrightSource,
729
860
  gen,
730
861
  genCmd
731
862
  };
732
- //# sourceMappingURL=chunk-PYKYHIO3.js.map
863
+ //# sourceMappingURL=chunk-A4IHRXON.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 sanitizeUrlIntentPhrase(value: string): string {\n return value\n .replace(/`+/g, ' ')\n .replace(/^\\/+/, ' ')\n .replace(/\\/[dgimsuvy]*$/i, ' ')\n .replace(/[\"']/g, ' ')\n .replace(/\\b(?:the|a|an|user|same|current)\\b/gi, ' ')\n .replace(/\\b(?:page|screen|view|area|section|route|path|url|form)\\b/gi, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nfunction pageNameToUrlPattern(value: string): string | undefined {\n const cleaned = sanitizeUrlIntentPhrase(value);\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 urlPatternFromIntentText(value: string): string | undefined {\n const sanitized = value.replace(/`+/g, '').trim();\n const explicitPathMatch =\n sanitized.match(/[\"'](\\/[^\"']+)[\"']/) ??\n sanitized.match(/\\b(?:to|on|at)\\s+(\\/[\\w/-]+)/i) ??\n sanitized.match(/https?:\\/\\/[^\\s'\"]+/i);\n const explicitPath = explicitPathMatch?.[1] ?? explicitPathMatch?.[0];\n if (explicitPath) {\n const fromUrl = explicitPath.startsWith('http') ? urlPatternFromAbsoluteUrl(explicitPath) : undefined;\n const fromPath = explicitPath.startsWith('/')\n ? explicitPath.replace(/^\\/+/, '').split('/').map(escapeForRegex).join('\\\\/')\n : undefined;\n return fromUrl ?? fromPath;\n }\n\n const phraseMatch =\n sanitized.match(/\\b(?:redirect(?:s|ed)?|navigat(?:e|es|ed)|go(?:es|ne)?|route|path|url)\\b(?:\\s+(?:to|on|contains))?\\s+(?:the\\s+)?(.+?)(?:[.?!]|$)/i) ??\n sanitized.match(/\\b(?:remain|remains|stays|stay|still)\\s+(?:on|at)\\s+(?:the\\s+)?(.+?)(?:[.?!]|$)/i);\n return phraseMatch?.[1] ? pageNameToUrlPattern(phraseMatch[1]) : undefined;\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 unwrapStepValue(value?: string): string | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n\n const quoted = parseQuotedLiteral(trimmed);\n if (quoted !== undefined) return quoted;\n\n const inlineCode = trimmed.match(/^`([^`]+)`$/);\n if (inlineCode) return inlineCode[1].trim();\n\n return trimmed;\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 = unwrapStepValue(value)?.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: unwrapStepValue(fillMatch[3]),\n };\n }\n\n const fillLooseMatch = s.match(/\\b(?:fill|input|write)\\s+(?:in\\s+)?(.+?)\\s+with\\s+(.+)$/i);\n if (fillLooseMatch) {\n return {\n kind: 'fill',\n rawField: fillLooseMatch[1].trim(),\n fieldLabel: cleanFieldLabel(fillLooseMatch[1]),\n value: unwrapStepValue(fillLooseMatch[2]),\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: unwrapStepValue(enterMatch[2]),\n };\n }\n\n const enterLooseMatch = s.match(/\\b(?:enter|type)\\s+(.+?)\\s+(?:in|into)\\s+(.+)$/i);\n if (enterLooseMatch) {\n return {\n kind: 'fill',\n rawField: enterLooseMatch[2].trim(),\n fieldLabel: cleanFieldLabel(enterLooseMatch[2]),\n value: unwrapStepValue(enterLooseMatch[1]),\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: unwrapStepValue(selectMatch[2]),\n };\n }\n\n const selectLooseMatch = s.match(/\\b(?:select|choose|pick)\\s+(.+?)\\s+(?:from|in|into|on)\\s+(.+)$/i);\n if (selectLooseMatch) {\n return {\n kind: 'select',\n rawField: selectLooseMatch[2].trim(),\n fieldLabel: cleanFieldLabel(selectLooseMatch[2]),\n value: unwrapStepValue(selectLooseMatch[1]),\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 inferNegativeAuthTarget(norm: NormalizedCase): 'EMAIL' | 'PASSWORD' | 'USERNAME' | undefined {\n const tags = (norm.tags ?? []).map(tag => tag.toLowerCase());\n const content = [norm.id, norm.title, ...(norm.expected ?? [])].filter(Boolean).join(' ').toLowerCase();\n const isNegativeCase = tags.includes('negative') || /\\b(invalid|wrong|incorrect|bad|nonexistent|not an email)\\b/.test(content);\n if (!isNegativeCase) return undefined;\n\n if (/\\b(?:invalid|wrong|incorrect|bad|not an email)\\s+(?:e-?mail|email)\\b|\\b(?:e-?mail|email)\\b.{0,24}\\b(?:invalid|wrong|incorrect|bad|not an email)\\b/.test(content)) {\n return 'EMAIL';\n }\n if (/\\b(?:invalid|wrong|incorrect|bad|nonexistent)\\s+(?:user(?:name)?|login)\\b|\\b(?:user(?:name)?|login)\\b.{0,24}\\b(?:invalid|wrong|incorrect|bad|nonexistent)\\b/.test(content)) {\n return 'USERNAME';\n }\n if (/\\b(?:invalid|wrong|incorrect|bad)\\s+password\\b|\\bpassword\\b.{0,24}\\b(?:invalid|wrong|incorrect|bad)\\b/.test(content)) {\n return 'PASSWORD';\n }\n\n return undefined;\n}\n\nfunction negativeAuthFallbackValue(target: 'EMAIL' | 'PASSWORD' | 'USERNAME'): string {\n return target === 'EMAIL'\n ? 'invalid-not-an-email'\n : target === 'PASSWORD'\n ? 'wrong-password-123'\n : 'nonexistent-user';\n}\n\nfunction rewriteNegativeAuthSteps(\n steps: string[],\n stepHints: Array<{ selector?: string }> | undefined,\n norm: NormalizedCase,\n): string[] {\n const target = inferNegativeAuthTarget(norm);\n if (!target) return steps;\n\n return steps.map((step, index) => {\n const binding = parseStepBinding(step);\n if (binding?.kind !== 'fill') return step;\n\n const selectorTarget = normalizeSelectorTarget(stepHints?.[index]?.selector);\n const fieldSuffix =\n fieldNameToEnvSuffix(binding.rawField) ??\n fieldNameToEnvSuffix(binding.fieldLabel) ??\n selectorTargetToEnvSuffix(selectorTarget);\n if (fieldSuffix !== target) return step;\n\n const rawField = binding.rawField ?? binding.fieldLabel ?? 'field';\n return `Fill in ${rawField} with '${negativeAuthFallbackValue(target)}'`;\n });\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 shouldUseRuntimeEnvValue =\n hasRuntimeEnvValue &&\n (!fallbackFromBinding || isGenericFallbackValue(fallbackFromBinding));\n const shouldDeclareVariable =\n binding.kind === 'select' ||\n templateEnvKey !== undefined ||\n overrideValue !== undefined ||\n shouldUseRuntimeEnvValue;\n\n let stepVar = shouldDeclareVariable ? seen.get(envKey) : undefined;\n if (shouldDeclareVariable && !stepVar) {\n const placeholderFallback =\n binding.kind === 'fill'\n ? buildFillPlaceholder(binding.rawField, binding.fieldLabel, selectorTarget)\n : assertionFallback ?? 'option';\n const fallback =\n overrideValue ??\n process.env[envKey] ??\n (templateEnvKey\n ? assertionFallback ?? placeholderFallback\n : ((!fallbackFromBinding || isGenericFallbackValue(fallbackFromBinding)) && assertionFallback\n ? assertionFallback\n : fallbackFromBinding)) ??\n placeholderFallback;\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 phraseToRegexPattern(value: string): string {\n return value\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n .map(token => escapeForRegex(token))\n .join('\\\\s+');\n}\n\nfunction buttonNameExpressionFromStep(step: string): string {\n const quotedMatch = step.match(/[\"']([^\"']+)[\"']/);\n if (quotedMatch) return `'${escapeForSingleQuotedString(quotedMatch[1])}'`;\n\n const label = step\n .replace(/^(click|press|tap)\\s+(?:on\\s+)?(?:the\\s+)?/i, '')\n .replace(/\\b(button|btn)\\b/gi, '')\n .replace(/[.?!,:;]+$/g, '')\n .trim();\n if (!label) return `'button'`;\n\n const lowered = label.toLowerCase();\n const variants = new Set<string>();\n if (/\\b(?:login|log in|sign in|sign-in)\\b/.test(lowered)) {\n variants.add('login');\n variants.add('log in');\n variants.add('sign in');\n } else if (/\\b(?:register|sign up|sign-up|signup|create account)\\b/.test(lowered)) {\n variants.add('register');\n variants.add('sign up');\n variants.add('create account');\n } else if (/\\bcontinue\\b/.test(lowered)) {\n variants.add('continue');\n variants.add('next');\n } else {\n variants.add(label);\n }\n\n const pattern = Array.from(variants).map(phraseToRegexPattern).join('|');\n return `/${pattern}/i`;\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 return `await page.getByRole('button', { name: ${buttonNameExpressionFromStep(s)} }).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 pagePattern = urlPatternFromIntentText(s);\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 finalPattern = urlPatternFromIntentText(s) ?? currentUrlPattern ?? '.+';\n return `await expect(page).toHaveURL(/${finalPattern}/);`;\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) => {\n const normalized = /^[A-Z0-9_]+$/.test(token) ? token.toLowerCase() : token;\n return normalized.charAt(0).toUpperCase() + normalized.slice(1);\n })\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 = rewriteNegativeAuthSteps(norm.steps ?? [], norm.step_hints, norm);\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\nconst PLAYWRIGHT_METHOD_NAMES = new Set([\n 'all',\n 'check',\n 'click',\n 'evaluate',\n 'fill',\n 'filter',\n 'first',\n 'getByLabel',\n 'getByPlaceholder',\n 'getByRole',\n 'getByTestId',\n 'getByText',\n 'goto',\n 'hover',\n 'locator',\n 'nth',\n 'or',\n 'press',\n 'reload',\n 'selectOption',\n 'toBeChecked',\n 'toBeDisabled',\n 'toBeEnabled',\n 'toBeHidden',\n 'toBeVisible',\n 'toContainText',\n 'toHaveCount',\n 'toHaveTitle',\n 'toHaveURL',\n 'toHaveValue',\n 'uncheck',\n 'waitForEvent',\n 'waitForLoad',\n 'waitForLoadState',\n]);\n\nfunction levenshteinDistance(left: string, right: string): number {\n const distances = Array.from({ length: right.length + 1 }, (_, index) => index);\n for (let row = 1; row <= left.length; row++) {\n let previousDiagonal = distances[0];\n distances[0] = row;\n for (let column = 1; column <= right.length; column++) {\n const temp = distances[column];\n distances[column] = Math.min(\n distances[column] + 1,\n distances[column - 1] + 1,\n previousDiagonal + (left[row - 1] === right[column - 1] ? 0 : 1),\n );\n previousDiagonal = temp;\n }\n }\n return distances[right.length];\n}\n\nfunction findClosestPlaywrightMethod(methodName: string): string | undefined {\n let bestCandidate: string | undefined;\n let bestDistance = Number.POSITIVE_INFINITY;\n\n for (const candidate of PLAYWRIGHT_METHOD_NAMES) {\n if (candidate[0] !== methodName[0]) continue;\n const distance = levenshteinDistance(methodName, candidate);\n if (distance < bestDistance) {\n bestDistance = distance;\n bestCandidate = candidate;\n }\n }\n\n return bestDistance <= 2 ? bestCandidate : undefined;\n}\n\nfunction stripBackticksInsideRegexLiterals(line: string): string {\n return line.includes('`') ? line.replace(/`/g, '') : line;\n}\n\nfunction repairPlaywrightMethodsInLine(line: string, fileLabel: string): string {\n if (!/\\bawait\\b/.test(line)) return line;\n\n return line.replace(/\\.(\\w+)\\(/g, (match, methodName: string) => {\n if (PLAYWRIGHT_METHOD_NAMES.has(methodName)) return match;\n\n const repaired = findClosestPlaywrightMethod(methodName);\n if (repaired) return `.${repaired}(`;\n\n throw new Error(`Generated unsupported Playwright method \".${methodName}(\" in ${fileLabel}`);\n });\n}\n\nexport function finalizeGeneratedPlaywrightSource(source: string, fileLabel: string): string {\n return source\n .split('\\n')\n .map((line) => repairPlaywrightMethodsInLine(stripBackticksInsideRegexLiterals(line), fileLabel))\n .join('\\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(\n pomFilePath,\n finalizeGeneratedPlaywrightSource(buildPomClass(pomClassName, norm, lang), pomFileName),\n );\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(\n specPath,\n finalizeGeneratedPlaywrightSource(\n buildSpecFile(norm, pomClassName, pomImportPath, varsOverride),\n basename(specPath),\n ),\n );\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":[]}
@@ -96,7 +96,7 @@ async function captureElements(url, options = {}) {
96
96
  headless = true,
97
97
  timeoutMs = DEFAULT_TIMEOUT_MS,
98
98
  verbose = false,
99
- userAgent = "Mozilla/5.0 (compatible; CementicTest/0.2.16 capture)"
99
+ userAgent = "Mozilla/5.0 (compatible; CementicTest/0.2.17 capture)"
100
100
  } = options;
101
101
  const chromium = await loadChromium();
102
102
  const mode = headless ? "headless" : "headed";
@@ -619,4 +619,4 @@ export {
619
619
  extractDomDataFromEnvironment,
620
620
  formatCaptureFailure
621
621
  };
622
- //# sourceMappingURL=chunk-WUGSOKKY.js.map
622
+ //# sourceMappingURL=chunk-JWGYAQ3O.js.map