@cementic/cementic-test 0.2.17 → 0.2.18

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.18
6
+
7
+ - stripped wrapping quote characters from captured and generated label-based selectors so values like `'Username'` now generate runnable `getByLabel('Username')` locators
8
+ - made generated auth field fills more resilient by adding locator fallbacks for label-based username, email, password, and select interactions
9
+ - fixed field-specific negative auth generation so only the field under test gets the invalid value while the other required auth fields stay valid
10
+ - mapped explicit leave-empty auth steps such as `Leave the password field empty` to `fill('')` instead of emitting `TODO` comments
11
+ - updated package metadata, capture artifact metadata, and capture user agent strings to `0.2.18`
12
+
5
13
  ## v0.2.17
6
14
 
7
15
  - 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/`
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.17 acceptance criteria
221
+ ### v0.2.18 acceptance criteria
222
222
 
223
- All of the following must be true before publishing `v0.2.17`:
223
+ All of the following must be true before publishing `v0.2.18`:
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`
@@ -463,6 +463,12 @@ And start automating.
463
463
 
464
464
  See [CHANGELOG.md](./CHANGELOG.md) for the full release history.
465
465
 
466
+ ### v0.2.18
467
+
468
+ - stripped wrapping quotes from captured label selectors before generating `getByLabel(...)` locators
469
+ - added resilient fallbacks for label-based auth field and select interactions
470
+ - fixed wrong-password negative generation so only the target field is invalid and leave-empty steps emit `fill('')`
471
+
466
472
  ### v0.2.17
467
473
 
468
474
  - 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/`
package/dist/capture.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  formatCaptureFailure,
7
7
  inferInteractiveRole,
8
8
  toPageSummary
9
- } from "./chunk-JWGYAQ3O.js";
9
+ } from "./chunk-GSQCM62X.js";
10
10
  export {
11
11
  CaptureRuntimeError,
12
12
  captureElements,
@@ -91,12 +91,24 @@ function inferInteractiveRole(tagName, attrs = {}) {
91
91
  }
92
92
  return void 0;
93
93
  }
94
+ function stripWrappingQuotes(value) {
95
+ if (!value) return void 0;
96
+ let trimmed = value.trim();
97
+ if (!trimmed) return void 0;
98
+ while (trimmed.length >= 2 && (trimmed.startsWith("'") && trimmed.endsWith("'") || trimmed.startsWith('"') && trimmed.endsWith('"'))) {
99
+ trimmed = trimmed.slice(1, -1).trim();
100
+ }
101
+ return trimmed || void 0;
102
+ }
103
+ function sanitizeLabelText(value) {
104
+ return stripWrappingQuotes(value)?.trim() || void 0;
105
+ }
94
106
  async function captureElements(url, options = {}) {
95
107
  const {
96
108
  headless = true,
97
109
  timeoutMs = DEFAULT_TIMEOUT_MS,
98
110
  verbose = false,
99
- userAgent = "Mozilla/5.0 (compatible; CementicTest/0.2.17 capture)"
111
+ userAgent = "Mozilla/5.0 (compatible; CementicTest/0.2.18 capture)"
100
112
  } = options;
101
113
  const chromium = await loadChromium();
102
114
  const mode = headless ? "headless" : "headed";
@@ -238,16 +250,18 @@ function extractDomDataFromEnvironment(doc, win) {
238
250
  }
239
251
  const ariaLabel = attr(el, "aria-label");
240
252
  if (ariaLabel) {
253
+ const sanitizedAriaLabel = sanitizeLabelText(ariaLabel) ?? ariaLabel;
241
254
  const role = semanticRole(el);
242
- if (role === "textbox") return `getByLabel(${jsString(ariaLabel)})`;
255
+ if (role === "textbox") return `getByLabel(${jsString(sanitizedAriaLabel)})`;
243
256
  if (role) {
244
- return `getByRole(${jsString(role)}, { name: ${jsString(ariaLabel)} })`;
257
+ return `getByRole(${jsString(role)}, { name: ${jsString(sanitizedAriaLabel)} })`;
245
258
  }
246
259
  }
247
- if (labelText) {
260
+ const sanitizedLabel = sanitizeLabelText(labelText);
261
+ if (sanitizedLabel) {
248
262
  const tag = el.tagName.toLowerCase();
249
263
  if (tag === "input" || tag === "textarea" || tag === "select") {
250
- return `getByLabel(${jsString(labelText)})`;
264
+ return `getByLabel(${jsString(sanitizedLabel)})`;
251
265
  }
252
266
  }
253
267
  if (buttonText) {
@@ -619,4 +633,4 @@ export {
619
633
  extractDomDataFromEnvironment,
620
634
  formatCaptureFailure
621
635
  };
622
- //# sourceMappingURL=chunk-JWGYAQ3O.js.map
636
+ //# sourceMappingURL=chunk-GSQCM62X.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/playwright.ts","../src/core/capture.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { createRequire } from 'node:module';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\n\ntype PlaywrightPackageName = '@playwright/test' | 'playwright-core';\n\nexport type PlaywrightResolution = {\n packageName: PlaywrightPackageName;\n resolvedPath: string;\n searchRoot: string;\n chromium: any;\n};\n\nconst require = createRequire(import.meta.url);\nconst moduleDir = dirname(fileURLToPath(import.meta.url));\n\nexport async function resolvePlaywrightChromium(cwd = process.cwd()): Promise<PlaywrightResolution> {\n const searchRoots = buildSearchRoots(cwd);\n\n for (const packageName of ['@playwright/test', 'playwright-core'] as const) {\n for (const searchRoot of searchRoots) {\n const resolvedPath = resolveFromRoot(packageName, searchRoot);\n if (!resolvedPath) continue;\n\n const imported = await import(pathToFileURL(resolvedPath).href);\n const chromium = imported.chromium ?? imported.default?.chromium;\n\n if (chromium) {\n return {\n packageName,\n resolvedPath,\n searchRoot,\n chromium,\n };\n }\n }\n }\n\n throw new Error(\n 'Playwright runtime not found in this project.\\n' +\n 'Try:\\n' +\n ' npm install\\n' +\n ' npx playwright install chromium'\n );\n}\n\nfunction buildSearchRoots(cwd: string): string[] {\n const roots = [resolve(cwd)];\n const projectRoot = findNearestProjectRoot(cwd);\n\n if (projectRoot && projectRoot !== roots[0]) {\n roots.push(projectRoot);\n }\n\n roots.push(moduleDir);\n return Array.from(new Set(roots));\n}\n\nfunction findNearestProjectRoot(startDir: string): string | undefined {\n let currentDir = resolve(startDir);\n\n while (true) {\n if (existsSync(join(currentDir, 'package.json'))) {\n return currentDir;\n }\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) return undefined;\n currentDir = parentDir;\n }\n}\n\nfunction resolveFromRoot(packageName: PlaywrightPackageName, searchRoot: string): string | undefined {\n try {\n return require.resolve(packageName, { paths: [searchRoot] });\n } catch {\n return undefined;\n }\n}\n","import { resolvePlaywrightChromium } from './playwright.js';\n\nexport type InputDescriptor = {\n label?: string;\n placeholder?: string;\n name?: string;\n type?: string;\n testId?: string;\n};\n\nexport type PageSummary = {\n url: string;\n title?: string;\n headings: string[];\n buttons: string[];\n links: string[];\n inputs: InputDescriptor[];\n landmarks: string[];\n rawLength: number;\n};\n\nexport type CaptureMode = 'headless' | 'headed';\nexport type CaptureConfidence = 'high' | 'medium' | 'low';\nexport type CaptureCategory = 'input' | 'button' | 'link' | 'heading' | 'status';\nexport type CaptureErrorCode = 'PLAYWRIGHT_NOT_FOUND' | 'BROWSER_NOT_INSTALLED' | 'PAGE_LOAD_FAILED' | 'CAPTURE_FAILED';\nexport type InteractiveElementRole = 'button' | 'link' | 'textbox' | 'checkbox';\n\nexport type CapturedElement = {\n category: CaptureCategory;\n role: string;\n name?: string;\n selector: string;\n selectorAlt: string[];\n purpose: string;\n confidence: CaptureConfidence;\n attributes: Record<string, unknown>;\n};\n\nexport type ElementMap = {\n url: string;\n title: string;\n timestamp: string;\n mode: CaptureMode;\n summary: {\n totalElements: number;\n byCategory: Partial<Record<CaptureCategory, number>>;\n };\n elements: CapturedElement[];\n warnings: string[];\n};\n\ntype CaptureOptions = {\n headless?: boolean;\n timeoutMs?: number;\n verbose?: boolean;\n userAgent?: string;\n};\n\ntype DomButton = {\n tag: string;\n role: InteractiveElementRole;\n text?: string;\n testId?: string;\n id?: string;\n type?: string;\n disabled: boolean;\n selector?: string | null;\n cssPath?: string | null;\n};\n\ntype DomInput = {\n tag: string;\n type: string;\n label?: string;\n placeholder?: string;\n name?: string;\n id?: string;\n testId?: string;\n required: boolean;\n selector?: string | null;\n cssPath?: string | null;\n};\n\ntype DomLink = {\n tag: string;\n role: InteractiveElementRole;\n text: string;\n href?: string;\n testId?: string;\n external: boolean;\n selector: string;\n};\n\ntype DomHeading = {\n level: string;\n text: string;\n selector: string;\n};\n\ntype DomStatusRegion = {\n role: string;\n ariaLive?: string;\n text?: string;\n selector: string;\n};\n\ntype DomForm = {\n id?: string;\n label?: string;\n action?: string;\n method: string;\n fieldCount: number;\n index: number;\n};\n\ntype DomData = {\n buttons: DomButton[];\n inputs: DomInput[];\n links: DomLink[];\n headings: DomHeading[];\n landmarks: Array<{ role: string; label: string }>;\n statusRegions: DomStatusRegion[];\n forms: DomForm[];\n pageUrl: string;\n pageTitle: string;\n};\n\ntype DomElementLike = {\n tagName: string;\n textContent?: string | null;\n previousElementSibling?: DomElementLike | null;\n getAttribute(name: string): string | null;\n hasAttribute(name: string): boolean;\n closest(selector: string): DomElementLike | null;\n querySelectorAll?(selector: string): ArrayLike<DomElementLike>;\n};\n\ntype DomDocumentLike = {\n title?: string;\n querySelector(selector: string): DomElementLike | null;\n querySelectorAll(selector: string): ArrayLike<DomElementLike>;\n getElementById(id: string): DomElementLike | null;\n};\n\ntype DomWindowLike = {\n location: {\n hostname: string;\n href: string;\n };\n};\n\nconst SETTLE_MS = 1200;\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst MAX_PER_CATEGORY = 50;\n\nexport class CaptureRuntimeError extends Error {\n code: CaptureErrorCode;\n\n constructor(code: CaptureErrorCode, message: string, options?: { cause?: unknown }) {\n super(message);\n this.name = 'CaptureRuntimeError';\n this.code = code;\n if (options?.cause !== undefined) {\n (this as Error & { cause?: unknown }).cause = options.cause;\n }\n }\n}\n\nexport function inferInteractiveRole(\n tagName: string,\n attrs: { role?: string; href?: string; type?: string } = {},\n): InteractiveElementRole | undefined {\n const tag = String(tagName ?? '').trim().toLowerCase();\n const explicitRole = String(attrs.role ?? '').trim().toLowerCase();\n const type = String(attrs.type ?? '').trim().toLowerCase();\n const href = String(attrs.href ?? '').trim();\n\n if (explicitRole === 'button') return 'button';\n if (explicitRole === 'link') return 'link';\n if (explicitRole === 'textbox') return 'textbox';\n if (explicitRole === 'checkbox') return 'checkbox';\n\n if (tag === 'a' && href) return 'link';\n if (tag === 'button') return 'button';\n if (tag === 'textarea') return 'textbox';\n if (tag === 'select') return 'textbox';\n if (tag === 'input') {\n if (type === 'submit' || type === 'button' || type === 'reset' || type === 'image') return 'button';\n if (type === 'checkbox') return 'checkbox';\n return 'textbox';\n }\n\n return undefined;\n}\n\nfunction stripWrappingQuotes(value?: string): string | undefined {\n if (!value) return undefined;\n let trimmed = value.trim();\n if (!trimmed) return undefined;\n\n while (\n trimmed.length >= 2 &&\n ((trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")) ||\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')))\n ) {\n trimmed = trimmed.slice(1, -1).trim();\n }\n\n return trimmed || undefined;\n}\n\nfunction sanitizeLabelText(value?: string): string | undefined {\n return stripWrappingQuotes(value)?.trim() || undefined;\n}\n\nexport async function captureElements(url: string, options: CaptureOptions = {}): Promise<ElementMap> {\n const {\n headless = true,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n verbose = false,\n userAgent = 'Mozilla/5.0 (compatible; CementicTest/0.2.18 capture)',\n } = options;\n\n const chromium = await loadChromium();\n const mode: CaptureMode = headless ? 'headless' : 'headed';\n log(verbose, `\\n[capture] Starting ${mode} capture: ${url}`);\n\n let browser: any;\n\n try {\n browser = await chromium.launch({\n headless,\n slowMo: headless ? 0 : 150,\n });\n } catch (error: any) {\n throw classifyCaptureError(error);\n }\n\n const context = await browser.newContext({\n userAgent,\n viewport: { width: 1280, height: 800 },\n ignoreHTTPSErrors: true,\n });\n\n const page = await context.newPage();\n\n try {\n log(verbose, ` -> Navigating (timeout: ${timeoutMs}ms)`);\n try {\n await page.goto(url, {\n waitUntil: 'domcontentloaded',\n timeout: timeoutMs,\n });\n } catch (error: any) {\n throw new CaptureRuntimeError(\n 'PAGE_LOAD_FAILED',\n `Page load failed for ${url}. ${error?.message ?? error}`,\n { cause: error },\n );\n }\n\n log(verbose, ` -> Waiting ${SETTLE_MS}ms for page settle`);\n await page.waitForTimeout(SETTLE_MS);\n\n log(verbose, ' -> Extracting accessibility snapshot');\n const a11ySnapshot = await getAccessibilitySnapshot(page, verbose);\n\n log(verbose, ' -> Extracting DOM data');\n const domData = await page.evaluate(extractDomData);\n\n const title = await page.title();\n const finalUrl = page.url();\n const elements = buildElementMap(domData);\n const warnings = buildWarnings(elements, domData, a11ySnapshot);\n const byCategory: Partial<Record<CaptureCategory, number>> = {};\n\n for (const element of elements) {\n byCategory[element.category] = (byCategory[element.category] ?? 0) + 1;\n }\n\n const result: ElementMap = {\n url: finalUrl,\n title,\n timestamp: new Date().toISOString(),\n mode,\n summary: {\n totalElements: elements.length,\n byCategory,\n },\n elements,\n warnings,\n };\n\n log(verbose, ` -> Captured ${elements.length} testable elements from \"${title}\"`);\n return result;\n } catch (error: any) {\n throw classifyCaptureError(error);\n } finally {\n await browser?.close();\n }\n}\n\nexport function toPageSummary(elementMap: ElementMap): PageSummary {\n const inputs = elementMap.elements\n .filter((element): element is CapturedElement => element.category === 'input')\n .slice(0, 30)\n .map((element) => ({\n label: asString(element.attributes.label),\n placeholder: asString(element.attributes.placeholder),\n name: asString(element.attributes.name),\n type: asString(element.attributes.type),\n testId: asString(element.attributes.testId),\n }));\n\n return {\n url: elementMap.url,\n title: elementMap.title,\n headings: elementMap.elements\n .filter((element) => element.category === 'heading')\n .map((element) => element.name ?? '')\n .filter(Boolean)\n .slice(0, 20),\n buttons: elementMap.elements\n .filter((element) => element.category === 'button')\n .map((element) => element.name ?? '')\n .filter(Boolean)\n .slice(0, 30),\n links: elementMap.elements\n .filter((element) => element.category === 'link')\n .map((element) => element.name ?? '')\n .filter(Boolean)\n .slice(0, 50),\n inputs,\n landmarks: [],\n rawLength: elementMap.elements.length,\n };\n}\n\nasync function loadChromium(): Promise<any> {\n try {\n const resolution = await resolvePlaywrightChromium(process.cwd());\n return resolution.chromium;\n } catch (error: any) {\n throw new CaptureRuntimeError(\n 'PLAYWRIGHT_NOT_FOUND',\n error?.message ??\n 'Playwright runtime not found in this project.\\nTry:\\n npm install\\n npx playwright install chromium',\n { cause: error },\n );\n }\n}\n\nexport function extractDomDataFromEnvironment(doc: DomDocumentLike, win: DomWindowLike): DomData {\n const localMaxPerCategory = 50;\n const attr = (el: DomElementLike, name: string): string | undefined => el.getAttribute(name)?.trim() || undefined;\n const text = (el: DomElementLike | null): string | undefined => el?.textContent?.replace(/\\s+/g, ' ').trim() || undefined;\n const jsString = (value: string) => JSON.stringify(value);\n const semanticRole = (el: DomElementLike): InteractiveElementRole | undefined => inferInteractiveRole(el.tagName, {\n role: attr(el, 'role'),\n href: attr(el, 'href'),\n type: attr(el, 'type'),\n });\n\n const findLabel = (el: DomElementLike): string | undefined => {\n const id = attr(el, 'id');\n\n if (id) {\n const labelEl = doc.querySelector(`label[for=\"${id}\"]`);\n if (labelEl) return text(labelEl);\n }\n\n const ariaLabel = attr(el, 'aria-label');\n if (ariaLabel) return ariaLabel;\n\n const labelledBy = attr(el, 'aria-labelledby');\n if (labelledBy) {\n const labelEl = doc.getElementById(labelledBy);\n if (labelEl) return text(labelEl);\n }\n\n const closestLabel = el.closest('label');\n if (closestLabel) {\n const raw = text(closestLabel) || '';\n const placeholder = attr(el, 'placeholder') || '';\n return raw.replace(placeholder, '').trim() || undefined;\n }\n\n const previous = el.previousElementSibling;\n if (previous?.tagName === 'LABEL') return text(previous);\n\n return undefined;\n };\n\n const buildSelector = (el: DomElementLike, labelText?: string, buttonText?: string): string | null => {\n const testId = attr(el, 'data-testid');\n if (testId) return `getByTestId(${jsString(testId)})`;\n\n const id = attr(el, 'id');\n if (id && !id.match(/^(ember|react|vue|ng|auto|rand)/i)) {\n return `locator(${jsString(`#${id}`)})`;\n }\n\n const ariaLabel = attr(el, 'aria-label');\n if (ariaLabel) {\n const sanitizedAriaLabel = sanitizeLabelText(ariaLabel) ?? ariaLabel;\n const role = semanticRole(el);\n if (role === 'textbox') return `getByLabel(${jsString(sanitizedAriaLabel)})`;\n if (role) {\n return `getByRole(${jsString(role)}, { name: ${jsString(sanitizedAriaLabel)} })`;\n }\n }\n\n const sanitizedLabel = sanitizeLabelText(labelText);\n if (sanitizedLabel) {\n const tag = el.tagName.toLowerCase();\n if (tag === 'input' || tag === 'textarea' || tag === 'select') {\n return `getByLabel(${jsString(sanitizedLabel)})`;\n }\n }\n\n if (buttonText) {\n const role = semanticRole(el);\n if (role === 'button' || role === 'link') {\n return `getByRole(${jsString(role)}, { name: ${jsString(buttonText)} })`;\n }\n }\n\n const name = attr(el, 'name');\n if (name) return `locator(${jsString(`[name=\"${name}\"]`)})`;\n\n return null;\n };\n\n const buttons: DomButton[] = [];\n Array.from(doc.querySelectorAll('button, [role=\"button\"], input[type=\"submit\"], input[type=\"button\"]')).forEach((el) => {\n const role = semanticRole(el);\n if (role !== 'button') return;\n const buttonText = attr(el, 'aria-label') || text(el) || attr(el, 'value');\n const testId = attr(el, 'data-testid');\n const id = attr(el, 'id');\n const type = attr(el, 'type');\n const disabled = el.hasAttribute('disabled') || el.getAttribute('aria-disabled') === 'true';\n const selector = buildSelector(el, undefined, buttonText);\n\n if (buttonText || testId) {\n buttons.push({\n tag: el.tagName.toLowerCase(),\n role,\n text: buttonText,\n testId,\n id,\n type,\n disabled,\n selector,\n cssPath: testId ? `[data-testid=\"${testId}\"]` : (id ? `#${id}` : null),\n });\n }\n });\n\n const inputs: DomInput[] = [];\n Array.from(doc.querySelectorAll('input:not([type=\"hidden\"]):not([type=\"submit\"]):not([type=\"button\"]), textarea, select')).forEach((el) => {\n const label = findLabel(el);\n const placeholder = attr(el, 'placeholder');\n const name = attr(el, 'name');\n const id = attr(el, 'id');\n const type = attr(el, 'type') || el.tagName.toLowerCase();\n const testId = attr(el, 'data-testid');\n const required = el.hasAttribute('required');\n const selector = buildSelector(el, label);\n\n if (label || placeholder || name || testId || id) {\n inputs.push({\n tag: el.tagName.toLowerCase(),\n type,\n label,\n placeholder,\n name,\n id,\n testId,\n required,\n selector,\n cssPath: testId ? `[data-testid=\"${testId}\"]` : (id ? `#${id}` : (name ? `[name=\"${name}\"]` : null)),\n });\n }\n });\n\n const links: DomLink[] = [];\n Array.from(doc.querySelectorAll('a[href]')).forEach((el) => {\n const role = semanticRole(el);\n if (role !== 'link') return;\n const linkText = attr(el, 'aria-label') || text(el);\n const href = attr(el, 'href');\n const testId = attr(el, 'data-testid');\n\n if (!linkText || href === '#') return;\n\n links.push({\n tag: el.tagName.toLowerCase(),\n role,\n text: linkText,\n href,\n testId,\n external: Boolean(href?.startsWith('http') && !href.includes(win.location.hostname)),\n selector: testId\n ? `getByTestId(${jsString(testId)})`\n : `getByRole('link', { name: ${jsString(linkText)} })`,\n });\n });\n\n const headings: DomHeading[] = [];\n Array.from(doc.querySelectorAll('h1, h2, h3')).forEach((el) => {\n const headingText = text(el);\n if (headingText) {\n headings.push({\n level: el.tagName.toLowerCase(),\n text: headingText,\n selector: `getByRole('heading', { name: ${jsString(headingText)} })`,\n });\n }\n });\n\n const landmarks: Array<{ role: string; label: string }> = [];\n Array.from(doc.querySelectorAll('[role], main, nav, header, footer, aside, section[aria-label]')).forEach((el) => {\n const role = attr(el, 'role') || el.tagName.toLowerCase();\n const label = attr(el, 'aria-label') || text(el)?.slice(0, 40);\n if (role && label) landmarks.push({ role, label });\n });\n\n const statusRegions: DomStatusRegion[] = [];\n Array.from(doc.querySelectorAll('[role=\"alert\"], [role=\"status\"], [aria-live]')).forEach((el) => {\n const role = attr(el, 'role') || 'live';\n statusRegions.push({\n role,\n ariaLive: attr(el, 'aria-live'),\n text: text(el),\n selector: el.getAttribute('role')\n ? `getByRole(${jsString(role)})`\n : `locator('[aria-live]')`,\n });\n });\n\n const forms: DomForm[] = [];\n Array.from(doc.querySelectorAll('form')).forEach((form, index) => {\n forms.push({\n id: attr(form, 'id'),\n label: attr(form, 'aria-label') || attr(form, 'aria-labelledby'),\n action: attr(form, 'action'),\n method: attr(form, 'method') || 'get',\n fieldCount: Array.from(form.querySelectorAll?.('input, textarea, select') ?? []).length,\n index,\n });\n });\n\n return {\n buttons: buttons.slice(0, localMaxPerCategory),\n inputs: inputs.slice(0, localMaxPerCategory),\n links: links.slice(0, localMaxPerCategory),\n headings: headings.slice(0, 20),\n landmarks,\n statusRegions,\n forms,\n pageUrl: win.location.href,\n pageTitle: doc.title ?? '',\n };\n}\n\nfunction extractDomData(): DomData {\n return extractDomDataFromEnvironment(\n document as unknown as DomDocumentLike,\n window as unknown as DomWindowLike,\n );\n}\n\nfunction buildElementMap(domData: DomData): CapturedElement[] {\n const elements: CapturedElement[] = [];\n\n for (const input of domData.inputs) {\n const displayName = input.label || input.placeholder || input.name || input.testId;\n if (!displayName) continue;\n\n const selector = input.selector\n || (input.testId ? `getByTestId(${JSON.stringify(input.testId)})` : null)\n || (input.label ? `getByLabel(${JSON.stringify(input.label)})` : null)\n || (input.id ? `locator(${JSON.stringify(`#${input.id}`)})` : null)\n || (input.name ? `locator(${JSON.stringify(`[name=\"${input.name}\"]`)})` : null)\n || `locator(${JSON.stringify(`${input.tag}[placeholder=\"${input.placeholder ?? ''}\"]`)})`;\n\n const selectorAlt: string[] = [];\n if (input.id && !selector.includes(`#${input.id}`)) selectorAlt.push(`locator(${JSON.stringify(`#${input.id}`)})`);\n if (input.name && !selector.includes(input.name)) selectorAlt.push(`locator(${JSON.stringify(`[name=\"${input.name}\"]`)})`);\n if (input.testId && !selector.includes(input.testId)) selectorAlt.push(`getByTestId(${JSON.stringify(input.testId)})`);\n if (input.placeholder && !selector.includes(input.placeholder)) selectorAlt.push(`getByPlaceholder(${JSON.stringify(input.placeholder)})`);\n if (input.label && !selector.includes(input.label)) selectorAlt.push(`getByLabel(${JSON.stringify(input.label)})`);\n\n elements.push({\n category: 'input',\n role: input.type === 'checkbox' ? 'checkbox' : 'textbox',\n name: displayName,\n selector,\n selectorAlt,\n purpose: input.required\n ? `Required ${input.type} field - \"${displayName}\"`\n : `${input.type} field - \"${displayName}\"`,\n confidence: input.testId || input.label || input.id ? 'high' : (input.placeholder ? 'medium' : 'low'),\n attributes: {\n type: input.type,\n label: input.label,\n placeholder: input.placeholder,\n name: input.name,\n id: input.id,\n testId: input.testId,\n required: input.required,\n tag: input.tag,\n },\n });\n }\n\n for (const button of domData.buttons) {\n const buttonRole = button.role || 'button';\n const displayName = button.text || button.testId;\n if (!displayName) continue;\n\n const selector = button.selector\n || (button.testId ? `getByTestId(${JSON.stringify(button.testId)})` : null)\n || (button.text ? `getByRole(${JSON.stringify(buttonRole)}, { name: ${JSON.stringify(button.text)} })` : null)\n || (button.id ? `locator(${JSON.stringify(`#${button.id}`)})` : null)\n || (button.tag === 'button' ? `locator('button')` : `locator('[role=\"button\"]')`);\n\n const selectorAlt: string[] = [];\n if (button.id && !selector.includes(button.id)) selectorAlt.push(`locator(${JSON.stringify(`#${button.id}`)})`);\n if (button.testId && !selector.includes(button.testId)) selectorAlt.push(`getByTestId(${JSON.stringify(button.testId)})`);\n if (button.text && !selector.includes(button.text)) selectorAlt.push(`getByText(${JSON.stringify(button.text)})`);\n if (button.cssPath) selectorAlt.push(`locator(${JSON.stringify(button.cssPath)})`);\n\n elements.push({\n category: 'button',\n role: buttonRole,\n name: displayName,\n selector,\n selectorAlt,\n purpose: button.disabled\n ? `Disabled button - \"${displayName}\"`\n : button.type === 'submit'\n ? `Form submit button - \"${displayName}\"`\n : `Button - \"${displayName}\"`,\n confidence: button.testId || button.text ? 'high' : (button.id ? 'medium' : 'low'),\n attributes: {\n text: button.text,\n testId: button.testId,\n id: button.id,\n type: button.type,\n disabled: button.disabled,\n tag: button.tag,\n role: buttonRole,\n },\n });\n }\n\n for (const link of domData.links) {\n const linkRole = link.role || 'link';\n elements.push({\n category: 'link',\n role: linkRole,\n name: link.text,\n selector: link.selector,\n selectorAlt: [\n ...(link.testId ? [`getByTestId(${JSON.stringify(link.testId)})`] : []),\n `getByText(${JSON.stringify(link.text)})`,\n ],\n purpose: link.external\n ? `External link to \"${link.href}\" - \"${link.text}\"`\n : `Internal navigation link - \"${link.text}\" -> ${link.href}`,\n confidence: link.testId ? 'high' : 'medium',\n attributes: {\n text: link.text,\n href: link.href,\n testId: link.testId,\n external: link.external,\n tag: link.tag,\n role: linkRole,\n },\n });\n }\n\n for (const heading of domData.headings) {\n elements.push({\n category: 'heading',\n role: 'heading',\n name: heading.text,\n selector: heading.selector,\n selectorAlt: [`getByText(${JSON.stringify(heading.text)})`],\n purpose: `Page ${heading.level} heading - use to assert the correct page or section loaded`,\n confidence: 'medium',\n attributes: {\n level: heading.level,\n text: heading.text,\n },\n });\n }\n\n for (const status of domData.statusRegions) {\n elements.push({\n category: 'status',\n role: status.role,\n name: status.text || status.role,\n selector: status.selector,\n selectorAlt: [],\n purpose: 'Live region - use to assert error messages, success toasts, and validation feedback',\n confidence: 'medium',\n attributes: {\n role: status.role,\n ariaLive: status.ariaLive,\n currentText: status.text,\n },\n });\n }\n\n return elements;\n}\n\nfunction buildWarnings(\n elements: CapturedElement[],\n domData: DomData,\n a11ySnapshot: unknown,\n): string[] {\n const warnings: string[] = [];\n\n if (!a11ySnapshot) {\n warnings.push('Playwright accessibility snapshot was unavailable. Capture continued using DOM extraction only.');\n }\n\n const lowConfidenceInputs = elements.filter((element) => element.category === 'input' && element.confidence === 'low');\n if (lowConfidenceInputs.length > 0) {\n warnings.push(\n `${lowConfidenceInputs.length} input(s) have low-confidence selectors. Consider adding data-testid attributes to: ${lowConfidenceInputs.map((element) => element.name).filter(Boolean).join(', ')}`\n );\n }\n\n if (domData.statusRegions.length === 0) {\n warnings.push('No ARIA alert or status regions detected. Error message assertions may need manual selector adjustments after generation.');\n }\n\n for (const form of domData.forms) {\n const hasSubmit = domData.buttons.some((button) => button.type === 'submit');\n if (form.fieldCount > 0 && !hasSubmit) {\n warnings.push(\n `Form ${form.id || `#${form.index}`} has ${form.fieldCount} field(s) but no detected submit button. It may use keyboard submit or a custom handler.`\n );\n }\n }\n\n if (domData.links.length >= MAX_PER_CATEGORY) {\n warnings.push(`Link count hit the ${MAX_PER_CATEGORY} capture limit. Generation will focus on forms and buttons.`);\n }\n\n const interactive = elements.filter((element) => (\n element.category === 'button' || element.category === 'input' || element.category === 'link'\n ));\n if (interactive.length === 0) {\n warnings.push('No interactive elements detected. The page may require authentication, render later than the current settle window, or be mostly static content.');\n }\n\n return warnings;\n}\n\nfunction log(verbose: boolean, message: string): void {\n if (verbose) console.log(message);\n}\n\nasync function getAccessibilitySnapshot(page: any, verbose: boolean): Promise<unknown> {\n if (!page.accessibility || typeof page.accessibility.snapshot !== 'function') {\n log(verbose, ' -> Accessibility snapshot API unavailable; continuing with DOM-only capture');\n return null;\n }\n\n try {\n return await page.accessibility.snapshot({ interestingOnly: false });\n } catch (error: any) {\n log(verbose, ` -> Accessibility snapshot failed (${error?.message ?? error}); continuing with DOM-only capture`);\n return null;\n }\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nexport function formatCaptureFailure(error: unknown): string[] {\n const resolved = classifyCaptureError(error);\n\n if (resolved.code === 'PLAYWRIGHT_NOT_FOUND') {\n return [\n 'Playwright not resolvable.',\n 'Playwright runtime not found in this project.',\n 'Try:',\n ' npm install',\n ' npx playwright install chromium',\n ];\n }\n\n if (resolved.code === 'BROWSER_NOT_INSTALLED') {\n return [\n 'Browser not installed.',\n 'Playwright resolved, but Chromium is not installed for this project.',\n 'Try:',\n ' npx playwright install chromium',\n ];\n }\n\n if (resolved.code === 'PAGE_LOAD_FAILED') {\n return [\n 'Page load failed.',\n resolved.message,\n ];\n }\n\n return [\n 'Capture failed.',\n resolved.message,\n ];\n}\n\nfunction classifyCaptureError(error: unknown): CaptureRuntimeError {\n if (error instanceof CaptureRuntimeError) {\n return error;\n }\n\n const message = errorMessage(error);\n\n if (isBrowserInstallError(message)) {\n return new CaptureRuntimeError(\n 'BROWSER_NOT_INSTALLED',\n 'Playwright resolved, but Chromium is not installed for this project.',\n { cause: error },\n );\n }\n\n if (isPlaywrightNotFoundError(message)) {\n return new CaptureRuntimeError(\n 'PLAYWRIGHT_NOT_FOUND',\n 'Playwright runtime not found in this project.',\n { cause: error },\n );\n }\n\n return new CaptureRuntimeError('CAPTURE_FAILED', message || 'Unknown capture failure.', { cause: error });\n}\n\nfunction isBrowserInstallError(message: string): boolean {\n return /Executable doesn't exist|browserType\\.launch: Executable doesn't exist|Please run the following command|playwright install/i.test(message);\n}\n\nfunction isPlaywrightNotFoundError(message: string): boolean {\n return /Playwright runtime not found|Cannot find package ['\"](?:@playwright\\/test|playwright-core)['\"]/i.test(message);\n}\n\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n return String(error ?? '');\n}\n"],"mappings":"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","names":["require"]}
@@ -11,6 +11,21 @@ function escapeForSingleQuotedString(value) {
11
11
  function escapeForRegex(value) {
12
12
  return value.replace(/[.*+?^${}()|[\]\\\/]/g, "\\$&");
13
13
  }
14
+ function stripWrappingQuotes(value) {
15
+ if (!value) return void 0;
16
+ let trimmed = value.trim();
17
+ if (!trimmed) return void 0;
18
+ while (trimmed.length >= 2 && (trimmed.startsWith("'") && trimmed.endsWith("'") || trimmed.startsWith('"') && trimmed.endsWith('"'))) {
19
+ trimmed = trimmed.slice(1, -1).trim();
20
+ }
21
+ return trimmed || void 0;
22
+ }
23
+ function sanitizeLabelText(value) {
24
+ return stripWrappingQuotes(value)?.trim() || void 0;
25
+ }
26
+ function escapeForDoubleQuotedString(value) {
27
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
28
+ }
14
29
  function normalizeUrlForComparison(value) {
15
30
  if (!value) return void 0;
16
31
  try {
@@ -69,25 +84,46 @@ function normalizeOverrideKey(value) {
69
84
  }
70
85
  function cleanFieldLabel(value) {
71
86
  if (!value) return void 0;
72
- const cleaned = value.replace(/[.?!,:;]+$/g, "").replace(/^(?:the|a|an)\s+/i, "").replace(/\s+(?:field|input|box|area|dropdown|combobox|select|menu)\b/gi, "").trim();
87
+ const cleaned = sanitizeLabelText(value)?.replace(/[.?!,:;]+$/g, "").replace(/^(?:the|a|an)\s+/i, "").replace(/\s+(?:field|input|box|area|dropdown|combobox|select|menu)\b/gi, "").trim();
73
88
  return cleaned || void 0;
74
89
  }
75
90
  function isPositionalFieldReference(value) {
76
- if (!value) return false;
77
- const cleaned = value.trim().toLowerCase();
91
+ const sanitized = sanitizeLabelText(value);
92
+ if (!sanitized) return false;
93
+ const cleaned = sanitized.trim().toLowerCase();
78
94
  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);
79
95
  }
80
96
  function fieldNameToEnvSuffix(value) {
81
- if (!value || isPositionalFieldReference(value)) return void 0;
82
- const cleaned = value.replace(/[.?!,:;]+$/g, "").replace(/^(?:the|a|an)\s+/i, "").replace(/\b(?:field|input|box|area|dropdown|combobox|select|menu)\b/gi, " ").trim();
97
+ const sanitized = sanitizeLabelText(value);
98
+ if (!sanitized || isPositionalFieldReference(sanitized)) return void 0;
99
+ const cleaned = sanitized.replace(/[.?!,:;]+$/g, "").replace(/^(?:the|a|an)\s+/i, "").replace(/\b(?:field|input|box|area|dropdown|combobox|select|menu)\b/gi, " ").trim();
83
100
  const suffix = sanitizeEnvSegment(cleaned);
84
101
  if (!suffix) return void 0;
85
102
  if (/^(?:FIELD|INPUT|BOX|AREA|DROPDOWN|COMBOBOX|SELECT|MENU)$/.test(suffix)) return void 0;
86
103
  return suffix;
87
104
  }
88
- function normalizeSelectorTarget(value) {
105
+ function sanitizeSelectorExpression(value) {
89
106
  if (!value) return void 0;
90
- const trimmed = value.trim();
107
+ let sanitized = value.trim();
108
+ if (!sanitized) return void 0;
109
+ const rewriteQuotedArg = (full, prefix, quote, raw) => {
110
+ const cleaned = sanitizeLabelText(raw) ?? raw.trim();
111
+ return `${prefix}${quote}${quote === '"' ? escapeForDoubleQuotedString(cleaned) : escapeForSingleQuotedString(cleaned)}${quote}`;
112
+ };
113
+ sanitized = sanitized.replace(
114
+ /((?:getByLabel|getByPlaceholder|getByTestId|getByText)\()(['"])(.*?)\2/g,
115
+ rewriteQuotedArg
116
+ );
117
+ sanitized = sanitized.replace(
118
+ /(getByRole\((['"])(?:textbox|searchbox|combobox|spinbutton)\2,\s*\{\s*name:\s*)(['"])(.*?)\3/g,
119
+ (full, prefix, _roleQuote, quote, raw) => rewriteQuotedArg(full, prefix, quote, raw)
120
+ );
121
+ return sanitized.replace(/\s+/g, " ");
122
+ }
123
+ function normalizeSelectorTarget(value) {
124
+ const sanitized = sanitizeSelectorExpression(value);
125
+ if (!sanitized) return void 0;
126
+ const trimmed = sanitized.trim();
91
127
  if (!trimmed) return void 0;
92
128
  return trimmed.replace(/^page\./, "").replace(/\s+/g, " ");
93
129
  }
@@ -135,7 +171,10 @@ function selectorTargetToEnvSuffix(value) {
135
171
  return sanitizeEnvSegment(locatorArg.replace(/^[#.]+/, ""));
136
172
  }
137
173
  const labelArg = quotedArg(/^(?:getByLabel|getByPlaceholder|getByTestId|getByText)\((['"])(.*?)\1/i) ?? quotedArg(/^getByRole\((['"])(?:textbox|searchbox|combobox|spinbutton)\1,\s*\{\s*name:\s*(['"])(.*?)\2/i, 3);
138
- if (labelArg) return fieldNameToEnvSuffix(labelArg) ?? sanitizeEnvSegment(labelArg);
174
+ if (labelArg) {
175
+ const sanitizedLabel = sanitizeLabelText(labelArg) ?? labelArg;
176
+ return fieldNameToEnvSuffix(sanitizedLabel) ?? sanitizeEnvSegment(sanitizedLabel);
177
+ }
139
178
  return void 0;
140
179
  }
141
180
  function isGenericFallbackValue(value) {
@@ -269,6 +308,12 @@ function inferNegativeAuthTarget(norm) {
269
308
  function negativeAuthFallbackValue(target) {
270
309
  return target === "EMAIL" ? "invalid-not-an-email" : target === "PASSWORD" ? "wrong-password-123" : "nonexistent-user";
271
310
  }
311
+ function validAuthTemplateValue(fieldSuffix) {
312
+ if (fieldSuffix === "EMAIL" || fieldSuffix === "USERNAME" || fieldSuffix === "PASSWORD") {
313
+ return `\${CT_VAR_${fieldSuffix}}`;
314
+ }
315
+ return void 0;
316
+ }
272
317
  function rewriteNegativeAuthSteps(steps, stepHints, norm) {
273
318
  const target = inferNegativeAuthTarget(norm);
274
319
  if (!target) return steps;
@@ -277,9 +322,14 @@ function rewriteNegativeAuthSteps(steps, stepHints, norm) {
277
322
  if (binding?.kind !== "fill") return step;
278
323
  const selectorTarget = normalizeSelectorTarget(stepHints?.[index]?.selector);
279
324
  const fieldSuffix = fieldNameToEnvSuffix(binding.rawField) ?? fieldNameToEnvSuffix(binding.fieldLabel) ?? selectorTargetToEnvSuffix(selectorTarget);
280
- if (fieldSuffix !== target) return step;
325
+ if (!fieldSuffix) return step;
281
326
  const rawField = binding.rawField ?? binding.fieldLabel ?? "field";
282
- return `Fill in ${rawField} with '${negativeAuthFallbackValue(target)}'`;
327
+ if (fieldSuffix === target) {
328
+ return `Fill in ${rawField} with '${negativeAuthFallbackValue(target)}'`;
329
+ }
330
+ const validTemplate = validAuthTemplateValue(fieldSuffix);
331
+ if (validTemplate) return `Fill in ${rawField} with \`${validTemplate}\``;
332
+ return step;
283
333
  });
284
334
  }
285
335
  function resolveStepVarOverride(overrides, envKey, keySuffix, rawField, fieldLabel) {
@@ -441,10 +491,89 @@ function rewriteValueAssertionToUseVariable(playwright, stepState) {
441
491
  if (!valueExpression) return void 0;
442
492
  return ensureStatement(`await expect(page.${parsed.target}).toHaveValue(${valueExpression})`);
443
493
  }
494
+ function parseEmptyFieldStep(step) {
495
+ const s = step.trim();
496
+ const patterns = [
497
+ /\bleave\s+(.+?)\s+(?:field|input|box|area)?\s*(?:empty|blank)\b/i,
498
+ /\b(?:do not|don't)\s+fill\s+(?:in\s+)?(.+?)\s*(?:field|input|box|area)?\b/i,
499
+ /\bskip\s+(?:filling\s+)?(.+?)\s*(?:field|input|box|area)?\b/i
500
+ ];
501
+ for (const pattern of patterns) {
502
+ const match = s.match(pattern);
503
+ if (!match?.[1]) continue;
504
+ const rawField = match[1].trim();
505
+ return {
506
+ rawField,
507
+ fieldLabel: cleanFieldLabel(rawField)
508
+ };
509
+ }
510
+ return void 0;
511
+ }
512
+ function selectorTokensForField(rawField, fieldLabel, selectorTarget) {
513
+ const suffix = fieldNameToEnvSuffix(rawField) ?? fieldNameToEnvSuffix(fieldLabel) ?? selectorTargetToEnvSuffix(selectorTarget);
514
+ const tokens = /* @__PURE__ */ new Set();
515
+ const add = (value) => {
516
+ const cleaned = cleanFieldLabel(value) ?? sanitizeLabelText(value);
517
+ if (!cleaned) return;
518
+ cleaned.toLowerCase().split(/[^a-z0-9]+/).map((token) => token.trim()).filter((token) => token.length >= 3).filter((token) => !/^(?:the|field|input|box|area|dropdown|combobox|select|menu)$/.test(token)).forEach((token) => tokens.add(token));
519
+ };
520
+ add(rawField);
521
+ add(fieldLabel);
522
+ switch (suffix) {
523
+ case "USERNAME":
524
+ tokens.add("username");
525
+ tokens.add("user");
526
+ break;
527
+ case "PASSWORD":
528
+ tokens.add("password");
529
+ tokens.add("pass");
530
+ break;
531
+ case "EMAIL":
532
+ tokens.add("email");
533
+ break;
534
+ default:
535
+ break;
536
+ }
537
+ return Array.from(tokens);
538
+ }
539
+ function buildFallbackSelector(kind, rawField, fieldLabel, selectorTarget) {
540
+ const tokens = selectorTokensForField(rawField, fieldLabel, selectorTarget);
541
+ const suffix = fieldNameToEnvSuffix(rawField) ?? fieldNameToEnvSuffix(fieldLabel) ?? selectorTargetToEnvSuffix(selectorTarget);
542
+ const selectors = /* @__PURE__ */ new Set();
543
+ if (kind === "fill" && suffix === "PASSWORD") selectors.add('input[type="password"]');
544
+ const baseTags = kind === "select" ? ["select"] : ["input", "textarea"];
545
+ const attributes = ["name", "id", "placeholder", "aria-label"];
546
+ for (const token of tokens) {
547
+ const escapedToken = escapeForDoubleQuotedString(token);
548
+ for (const tag of baseTags) {
549
+ for (const attribute of attributes) {
550
+ selectors.add(`${tag}[${attribute}*="${escapedToken}" i]`);
551
+ }
552
+ }
553
+ }
554
+ if (selectors.size === 0) return void 0;
555
+ return Array.from(selectors).join(", ");
556
+ }
557
+ function buildFieldLocatorExpression(kind, rawField, fieldLabel, selectorTarget) {
558
+ const normalizedSelector = normalizeSelectorTarget(selectorTarget);
559
+ if (normalizedSelector && !/^getByLabel\(/i.test(normalizedSelector)) {
560
+ return `page.${normalizedSelector}`;
561
+ }
562
+ const sanitizedField = sanitizeLabelText(fieldLabel);
563
+ const labelMatch = normalizedSelector?.match(/^getByLabel\((['"])(.*?)\1\)$/i);
564
+ const labelText = sanitizedField ?? sanitizeLabelText(labelMatch?.[2]);
565
+ if (!labelText) {
566
+ return normalizedSelector ? `page.${normalizedSelector}` : void 0;
567
+ }
568
+ const baseLocator = normalizedSelector ? `page.${normalizedSelector}` : `page.getByLabel('${escapeForSingleQuotedString(labelText)}')`;
569
+ const fallbackSelector = buildFallbackSelector(kind, rawField, labelText, normalizedSelector);
570
+ if (!fallbackSelector) return baseLocator;
571
+ return `${baseLocator}.or(page.locator(${JSON.stringify(fallbackSelector)})).first()`;
572
+ }
444
573
  function stepToPlaywright(step, url, hint, stepVar) {
445
574
  const s = step.trim();
446
- const hintedSelector = hint?.selector ? `page.${hint.selector}` : void 0;
447
575
  const selectorTarget = normalizeSelectorTarget(hint?.selector);
576
+ const hintedSelector = selectorTarget ? `page.${selectorTarget}` : void 0;
448
577
  const valueExpression = (value) => stepVar?.constName ?? `'${escapeForSingleQuotedString(value)}'`;
449
578
  if (/^(navigate|go to|open|visit|load)/i.test(s)) {
450
579
  const urlMatch = s.match(/https?:\/\/[^\s'"]+/) || s.match(/["']([^"']+)["']/);
@@ -454,10 +583,19 @@ function stepToPlaywright(step, url, hint, stepVar) {
454
583
  }
455
584
  return `await page.goto('${escapeForSingleQuotedString(dest)}');`;
456
585
  }
586
+ const emptyField = parseEmptyFieldStep(s);
587
+ if (emptyField) {
588
+ const locatorExpression = buildFieldLocatorExpression("fill", emptyField.rawField, emptyField.fieldLabel, selectorTarget) ?? hintedSelector;
589
+ if (locatorExpression) {
590
+ const fieldDescription = sanitizeLabelText(emptyField.fieldLabel ?? emptyField.rawField) ?? "field";
591
+ return `await ${locatorExpression}.fill(''); // ${fieldDescription} intentionally left empty for validation`;
592
+ }
593
+ }
457
594
  const binding = parseStepBinding(s);
458
595
  if (binding?.kind === "fill") {
459
596
  const fallbackValue = stepVar?.fallback ?? resolveLiteralFillValue(binding, selectorTarget);
460
- if (hintedSelector) return `await ${hintedSelector}.fill(${valueExpression(fallbackValue)});`;
597
+ const locatorExpression = buildFieldLocatorExpression("fill", binding.rawField, binding.fieldLabel, selectorTarget) ?? hintedSelector;
598
+ if (locatorExpression) return `await ${locatorExpression}.fill(${valueExpression(fallbackValue)});`;
461
599
  const field = binding.fieldLabel ?? "field";
462
600
  return `await page.getByLabel('${escapeForSingleQuotedString(field)}').fill(${valueExpression(fallbackValue)});`;
463
601
  }
@@ -480,7 +618,8 @@ function stepToPlaywright(step, url, hint, stepVar) {
480
618
  }
481
619
  if (binding?.kind === "select") {
482
620
  const fallbackValue = binding.value ?? stepVar?.fallback ?? "option";
483
- if (hintedSelector) return `await ${hintedSelector}.selectOption(${valueExpression(fallbackValue)});`;
621
+ const locatorExpression = buildFieldLocatorExpression("select", binding.rawField, binding.fieldLabel, selectorTarget) ?? hintedSelector;
622
+ if (locatorExpression) return `await ${locatorExpression}.selectOption(${valueExpression(fallbackValue)});`;
484
623
  if (binding.fieldLabel) {
485
624
  return `await page.getByLabel('${escapeForSingleQuotedString(binding.fieldLabel)}').selectOption(${valueExpression(fallbackValue)});`;
486
625
  }
@@ -773,6 +912,9 @@ function findClosestPlaywrightMethod(methodName) {
773
912
  function stripBackticksInsideRegexLiterals(line) {
774
913
  return line.includes("`") ? line.replace(/`/g, "") : line;
775
914
  }
915
+ function sanitizeQuotedSelectorArgsInLine(line) {
916
+ return sanitizeSelectorExpression(line) ?? line;
917
+ }
776
918
  function repairPlaywrightMethodsInLine(line, fileLabel) {
777
919
  if (!/\bawait\b/.test(line)) return line;
778
920
  return line.replace(/\.(\w+)\(/g, (match, methodName) => {
@@ -783,7 +925,10 @@ function repairPlaywrightMethodsInLine(line, fileLabel) {
783
925
  });
784
926
  }
785
927
  function finalizeGeneratedPlaywrightSource(source, fileLabel) {
786
- return source.split("\n").map((line) => repairPlaywrightMethodsInLine(stripBackticksInsideRegexLiterals(line), fileLabel)).join("\n");
928
+ return source.split("\n").map((line) => repairPlaywrightMethodsInLine(
929
+ sanitizeQuotedSelectorArgsInLine(stripBackticksInsideRegexLiterals(line)),
930
+ fileLabel
931
+ )).join("\n");
787
932
  }
788
933
  async function gen(opts) {
789
934
  if (opts.lang !== "ts" && opts.lang !== "js") {
@@ -860,4 +1005,4 @@ export {
860
1005
  gen,
861
1006
  genCmd
862
1007
  };
863
- //# sourceMappingURL=chunk-A4IHRXON.js.map
1008
+ //# sourceMappingURL=chunk-P6WZO7G7.js.map