@cementic/cementic-test 0.2.14 → 0.2.16
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 +84 -0
- package/README.md +27 -3
- package/dist/capture.js +18 -0
- package/dist/{chunk-3S26OWNR.js → chunk-PYKYHIO3.js} +72 -9
- package/dist/chunk-PYKYHIO3.js.map +1 -0
- package/dist/chunk-WUGSOKKY.js +622 -0
- package/dist/chunk-WUGSOKKY.js.map +1 -0
- package/dist/cli.js +76 -594
- package/dist/cli.js.map +1 -1
- package/dist/{gen-AGWFMHTO.js → gen-WYG3JOGJ.js} +2 -2
- package/dist/gen-WYG3JOGJ.js.map +1 -0
- package/package.json +4 -3
- package/dist/chunk-3S26OWNR.js.map +0 -1
- /package/dist/{gen-AGWFMHTO.js.map → capture.js.map} +0 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@cementic/cementic-test` are documented here.
|
|
4
|
+
|
|
5
|
+
## v0.2.16
|
|
6
|
+
|
|
7
|
+
- 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
|
|
8
|
+
- fixed generated auth button clicks so generic phrases like `Click the login button` use resilient role-name regex matching when an exact accessible name is unavailable
|
|
9
|
+
- added regression coverage for unquoted `CT_VAR_*` auth steps to keep generated login specs runnable
|
|
10
|
+
- hardened the publish workflow so release tags must match `package.json`, and publishing aborts if the npm version already exists
|
|
11
|
+
- updated package metadata, capture artifact metadata, and capture user agent strings to `0.2.16`
|
|
12
|
+
|
|
13
|
+
## v0.2.15
|
|
14
|
+
|
|
15
|
+
- fixed capture semantics so `<a href="...">` elements are classified as links unless they explicitly expose `role="button"`
|
|
16
|
+
- made CTA-like presence selectors resilient by generating `Locator.or(...)` fallbacks across button and link roles when the intent is ambiguous
|
|
17
|
+
- tightened intent label cleanup so trailing filler phrases like `on the page` do not leak into generated locator text
|
|
18
|
+
- updated capture artifact metadata and capture user agent version strings to `0.2.15`
|
|
19
|
+
|
|
20
|
+
## v0.2.14
|
|
21
|
+
|
|
22
|
+
- hardened the release gate so `npm test` now includes the prompt regression suite and `prepublishOnly` runs the full test gate
|
|
23
|
+
- fixed the prompt test harness so it executes the local `dist/cli.js` build instead of depending on whichever global `ct` happens to be on `PATH`
|
|
24
|
+
- added deterministic capture-analysis fallback for `ct tc url --ai` when no LLM key is configured or remote analysis fails
|
|
25
|
+
- hardened auth, navigation, negative-state, heading, and count scenario fallback behavior so capture-driven generation still produces intent-aligned Playwright output offline
|
|
26
|
+
- added smoke coverage for `ct new`, `ct ci`, `ct flow --no-run`, `ct report`, and both `ct serve` execution paths
|
|
27
|
+
- replaced the old browser bootstrap heuristic in `ct new` with explicit browser install profiles: `auto`, `all`, and `chromium`
|
|
28
|
+
- kept the compatibility downgrade conditional to affected older macOS versions only, while preserving the normal Playwright install path for newer machines
|
|
29
|
+
- changed `ct new --mode` handling to reject unsupported scaffold modes explicitly instead of silently behaving like `greenfield`
|
|
30
|
+
|
|
31
|
+
## v0.2.13
|
|
32
|
+
|
|
33
|
+
- replaced the old Rule 10 prompt guidance with a Playwright knowledge base aligned to official Playwright docs and web-first assertion patterns
|
|
34
|
+
- aligned locator priority with Playwright best practices: `getByRole -> getByLabel -> getByPlaceholder -> getByText -> locator`
|
|
35
|
+
- made counting intents generate `toHaveCount()` or `.count()` instead of intent-text locators
|
|
36
|
+
- enforced that intent wording is never reused as locator text
|
|
37
|
+
- made negative assertions generate `.not.` or `toBeHidden()` patterns
|
|
38
|
+
- made error assertions prefer `getByRole('alert')` and heading assertions prefer `getByRole('heading')`
|
|
39
|
+
- added on-demand Playwright doc fetching for advanced categories such as uploads, mocking, accessibility, viewports, auth, downloads, dialogs, frames, and popups
|
|
40
|
+
- added the 12-check prompt regression suite in `test/prompt.spec.mjs`
|
|
41
|
+
|
|
42
|
+
## v0.2.12
|
|
43
|
+
|
|
44
|
+
- made both AI generation paths intent-first so markdown and capture-based scenario generation follow the same scope and presence-only rules
|
|
45
|
+
- tightened capture-based scenario generation to preserve presence-only checks as visibility assertions, honor intent-based selector fallback, and avoid generic `'value'` placeholders
|
|
46
|
+
- added regression coverage for the new markdown prompt contract and capture-path intent enforcement
|
|
47
|
+
- breaking change: none
|
|
48
|
+
|
|
49
|
+
## v0.2.11
|
|
50
|
+
|
|
51
|
+
- AI no longer writes `'value'` as a step input and now prefers matching `CT_VAR_*` references or `test-{fieldname}` fallbacks
|
|
52
|
+
- fixed `ct gen` so generic fill steps read matching `CT_VAR_*` values from the environment and emit env-backed constants only when they are actually needed
|
|
53
|
+
- fixed generated `toHaveValue(...)` assertions so they reuse the same emitted fill value for selector-backed form fields
|
|
54
|
+
- added a generated spec header comment that lists required `CT_VAR_*` variables with inline usage examples
|
|
55
|
+
- breaking change: none
|
|
56
|
+
|
|
57
|
+
## v0.2.10
|
|
58
|
+
|
|
59
|
+
- fixed `ct gen` so selector-hinted fields like `#username` and `#password` infer matching `CT_VAR_*` constants instead of leaving `.fill('value')` placeholders behind
|
|
60
|
+
- fixed generated `toHaveValue(...)` assertions so they reuse the same `CT_VAR_*` binding when the related fill step was variablized
|
|
61
|
+
- added regression coverage for selector-driven auth generation to keep fill calls and value assertions aligned
|
|
62
|
+
|
|
63
|
+
## v0.2.9
|
|
64
|
+
|
|
65
|
+
- added `CT_VAR_*` extraction in `ct gen` for input and select test data so generated specs use env-backed constants instead of hardcoded values
|
|
66
|
+
- added `ct gen --vars '{...}'` to override generated fallback values without editing the emitted spec files by hand
|
|
67
|
+
- added regression coverage for variableized generated specs, selector-hint preservation, and select-option extraction
|
|
68
|
+
|
|
69
|
+
## v0.2.8
|
|
70
|
+
|
|
71
|
+
- fixed TypeScript generator identifier sanitization so scenario titles containing em dashes and other non-identifier characters no longer break generated POM class names or spec imports
|
|
72
|
+
- added regression coverage for generated TypeScript output from scenario titles like `Login-002 — User can enter credentials — before submission`
|
|
73
|
+
|
|
74
|
+
## v0.2.7
|
|
75
|
+
|
|
76
|
+
- fixed project-first Playwright resolution for `ct tc url --ai`, including global and `npx` CLI usage
|
|
77
|
+
- added clearer capture failure categories and setup guidance for missing Playwright, missing browsers, and page-load failures
|
|
78
|
+
- centralized AI provider detection so `tc --ai` and capture analysis recognize the same providers and env vars
|
|
79
|
+
- fixed missing DeepSeek guidance in the CLI help path
|
|
80
|
+
- changed legacy macOS browser setup to install Chromium only by default and avoid WebKit unsupported failures
|
|
81
|
+
|
|
82
|
+
## v0.2.6
|
|
83
|
+
|
|
84
|
+
- added an install-time banner with links to the website and community
|
package/README.md
CHANGED
|
@@ -206,6 +206,8 @@ Before publishing, run the full local gate:
|
|
|
206
206
|
npm test
|
|
207
207
|
```
|
|
208
208
|
|
|
209
|
+
Do not reuse an npm version. npm will reject republishing an existing version even if the Git tag was moved later.
|
|
210
|
+
|
|
209
211
|
If you want to inspect the prompt regression suite directly:
|
|
210
212
|
|
|
211
213
|
```bash
|
|
@@ -216,16 +218,20 @@ node --test --test-name-pattern="counting intent" test/prompt.spec.mjs
|
|
|
216
218
|
|
|
217
219
|
Note: on current Node test runner versions, use `--test-reporter=spec`, not `--reporter=spec`.
|
|
218
220
|
|
|
219
|
-
### v0.2.
|
|
221
|
+
### v0.2.16 acceptance criteria
|
|
220
222
|
|
|
221
|
-
All of the following must be true before publishing `v0.2.
|
|
223
|
+
All of the following must be true before publishing `v0.2.16`:
|
|
222
224
|
|
|
223
225
|
- `npm test` passes from a clean checkout and includes both the integration suite and `test/prompt.spec.mjs`
|
|
224
226
|
- `prepublishOnly` runs the same full release gate, not just `build`
|
|
227
|
+
- the release tag matches `package.json`
|
|
228
|
+
- the target npm version is not already published
|
|
225
229
|
- prompt regression suite verifies:
|
|
226
230
|
- counting intents generate `toHaveCount()` or `.count()`
|
|
227
231
|
- intent text is never reused as `getByText(...)`
|
|
228
232
|
- presence-only intents generate visibility assertions without click steps
|
|
233
|
+
- CTA-like presence intents can fall back from `button` to `link` selectors with `Locator.or(...)`
|
|
234
|
+
- counting button intents exclude CTA links that are really anchors
|
|
229
235
|
- generated specs always use `await expect(...)`
|
|
230
236
|
- auth/navigation intents generate `toHaveURL(...)`
|
|
231
237
|
- negative intents generate `.not.` or `toBeHidden()`
|
|
@@ -236,6 +242,7 @@ All of the following must be true before publishing `v0.2.14`:
|
|
|
236
242
|
- `ct tc url --ai` works in both modes:
|
|
237
243
|
- with an LLM key, capture analysis remains intent-first and selector-safe
|
|
238
244
|
- without an LLM key, deterministic capture-backed scenario generation still produces runnable, intent-aligned output
|
|
245
|
+
- capture semantics never classify `<a href="...">` as a button unless `role="button"` is explicit
|
|
239
246
|
- `ct normalize` preserves:
|
|
240
247
|
- `ct:url` metadata
|
|
241
248
|
- selector hints
|
|
@@ -243,8 +250,10 @@ All of the following must be true before publishing `v0.2.14`:
|
|
|
243
250
|
- review flags and review reasons
|
|
244
251
|
- `ct gen` guarantees:
|
|
245
252
|
- no `.fill('value')` placeholders
|
|
253
|
+
- no `TODO` comments for recognized fill/select auth steps using quoted, unquoted, or backticked `CT_VAR_*` values
|
|
246
254
|
- env-backed `CT_VAR_*` extraction when matching vars are available
|
|
247
255
|
- field-specific fallback values when env vars are not available
|
|
256
|
+
- generic auth button click steps fall back to resilient role-name matching when exact labels are missing
|
|
248
257
|
- existing POM files are not overwritten
|
|
249
258
|
- generated specs compile as valid Playwright TypeScript or JavaScript
|
|
250
259
|
- command smoke coverage passes for:
|
|
@@ -255,7 +264,7 @@ All of the following must be true before publishing `v0.2.14`:
|
|
|
255
264
|
- unsupported `ct new --mode` values failing explicitly
|
|
256
265
|
- `ct ci`
|
|
257
266
|
- `ct flow --no-run`
|
|
258
|
-
- README, package version, and
|
|
267
|
+
- README, package version, runtime metadata strings, and changelog entries match the release being cut
|
|
259
268
|
|
|
260
269
|
---
|
|
261
270
|
|
|
@@ -448,6 +457,21 @@ And start automating.
|
|
|
448
457
|
|
|
449
458
|
## Changelog
|
|
450
459
|
|
|
460
|
+
See [CHANGELOG.md](./CHANGELOG.md) for the full release history.
|
|
461
|
+
|
|
462
|
+
### v0.2.16
|
|
463
|
+
|
|
464
|
+
- fixed `ct gen` so unquoted and backticked `CT_VAR_*` fill steps now generate runnable `.fill()` calls instead of `TODO` comments
|
|
465
|
+
- made generated auth button clicks more resilient for generic phrases like `Click the login button`
|
|
466
|
+
- added release guards so publish only proceeds when the Git tag matches `package.json` and the npm version has not already been published
|
|
467
|
+
|
|
468
|
+
### v0.2.15
|
|
469
|
+
|
|
470
|
+
- fixed capture semantics so `<a href="...">` elements are classified as links unless they explicitly expose `role="button"`
|
|
471
|
+
- made CTA-like presence selectors resilient by generating `Locator.or(...)` fallbacks across button and link roles when the intent is ambiguous
|
|
472
|
+
- tightened intent label cleanup so trailing filler phrases like `on the page` do not leak into generated locator text
|
|
473
|
+
- updated capture artifact metadata and capture user agent version strings to `0.2.15`
|
|
474
|
+
|
|
451
475
|
### v0.2.14
|
|
452
476
|
|
|
453
477
|
- hardened the release gate so `npm test` now includes the prompt regression suite and `prepublishOnly` runs the full test gate
|
package/dist/capture.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
CaptureRuntimeError,
|
|
4
|
+
captureElements,
|
|
5
|
+
extractDomDataFromEnvironment,
|
|
6
|
+
formatCaptureFailure,
|
|
7
|
+
inferInteractiveRole,
|
|
8
|
+
toPageSummary
|
|
9
|
+
} from "./chunk-WUGSOKKY.js";
|
|
10
|
+
export {
|
|
11
|
+
CaptureRuntimeError,
|
|
12
|
+
captureElements,
|
|
13
|
+
extractDomDataFromEnvironment,
|
|
14
|
+
formatCaptureFailure,
|
|
15
|
+
inferInteractiveRole,
|
|
16
|
+
toPageSummary
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=capture.js.map
|
|
@@ -92,6 +92,16 @@ function parseQuotedLiteral(value) {
|
|
|
92
92
|
}
|
|
93
93
|
return void 0;
|
|
94
94
|
}
|
|
95
|
+
function unwrapStepValue(value) {
|
|
96
|
+
if (!value) return void 0;
|
|
97
|
+
const trimmed = value.trim();
|
|
98
|
+
if (!trimmed) return void 0;
|
|
99
|
+
const quoted = parseQuotedLiteral(trimmed);
|
|
100
|
+
if (quoted !== void 0) return quoted;
|
|
101
|
+
const inlineCode = trimmed.match(/^`([^`]+)`$/);
|
|
102
|
+
if (inlineCode) return inlineCode[1].trim();
|
|
103
|
+
return trimmed;
|
|
104
|
+
}
|
|
95
105
|
function selectorTargetToEnvSuffix(value) {
|
|
96
106
|
const selector = normalizeSelectorTarget(value);
|
|
97
107
|
if (!selector) return void 0;
|
|
@@ -118,7 +128,7 @@ function isGenericFallbackValue(value) {
|
|
|
118
128
|
return /^(?:value|text|input|option|selection|selected value|default)$/i.test(value.trim());
|
|
119
129
|
}
|
|
120
130
|
function extractCtVarTemplate(value) {
|
|
121
|
-
const match = value?.
|
|
131
|
+
const match = unwrapStepValue(value)?.match(/^\$\{(CT_VAR_[A-Z0-9_]+)\}$/);
|
|
122
132
|
return match?.[1];
|
|
123
133
|
}
|
|
124
134
|
function placeholderTokenFromSuffix(value) {
|
|
@@ -151,7 +161,16 @@ function parseStepBinding(step) {
|
|
|
151
161
|
kind: "fill",
|
|
152
162
|
rawField: fillMatch[1].trim(),
|
|
153
163
|
fieldLabel: cleanFieldLabel(fillMatch[1]),
|
|
154
|
-
value: fillMatch[3]
|
|
164
|
+
value: unwrapStepValue(fillMatch[3])
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
const fillLooseMatch = s.match(/\b(?:fill|input|write)\s+(?:in\s+)?(.+?)\s+with\s+(.+)$/i);
|
|
168
|
+
if (fillLooseMatch) {
|
|
169
|
+
return {
|
|
170
|
+
kind: "fill",
|
|
171
|
+
rawField: fillLooseMatch[1].trim(),
|
|
172
|
+
fieldLabel: cleanFieldLabel(fillLooseMatch[1]),
|
|
173
|
+
value: unwrapStepValue(fillLooseMatch[2])
|
|
155
174
|
};
|
|
156
175
|
}
|
|
157
176
|
const fillWithoutValueMatch = s.match(/\b(?:fill|input|write)\s+(?:in\s+)?(.+?)$/i);
|
|
@@ -168,7 +187,16 @@ function parseStepBinding(step) {
|
|
|
168
187
|
kind: "fill",
|
|
169
188
|
rawField: enterMatch[3].trim(),
|
|
170
189
|
fieldLabel: cleanFieldLabel(enterMatch[3]),
|
|
171
|
-
value: enterMatch[2]
|
|
190
|
+
value: unwrapStepValue(enterMatch[2])
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
const enterLooseMatch = s.match(/\b(?:enter|type)\s+(.+?)\s+(?:in|into)\s+(.+)$/i);
|
|
194
|
+
if (enterLooseMatch) {
|
|
195
|
+
return {
|
|
196
|
+
kind: "fill",
|
|
197
|
+
rawField: enterLooseMatch[2].trim(),
|
|
198
|
+
fieldLabel: cleanFieldLabel(enterLooseMatch[2]),
|
|
199
|
+
value: unwrapStepValue(enterLooseMatch[1])
|
|
172
200
|
};
|
|
173
201
|
}
|
|
174
202
|
const enterWithoutValueMatch = s.match(/\b(?:enter|type)\s+(?:in|into)\s+(.+)/i);
|
|
@@ -185,7 +213,16 @@ function parseStepBinding(step) {
|
|
|
185
213
|
kind: "select",
|
|
186
214
|
rawField: selectMatch[3].trim(),
|
|
187
215
|
fieldLabel: cleanFieldLabel(selectMatch[3]),
|
|
188
|
-
value: selectMatch[2]
|
|
216
|
+
value: unwrapStepValue(selectMatch[2])
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
const selectLooseMatch = s.match(/\b(?:select|choose|pick)\s+(.+?)\s+(?:from|in|into|on)\s+(.+)$/i);
|
|
220
|
+
if (selectLooseMatch) {
|
|
221
|
+
return {
|
|
222
|
+
kind: "select",
|
|
223
|
+
rawField: selectLooseMatch[2].trim(),
|
|
224
|
+
fieldLabel: cleanFieldLabel(selectLooseMatch[2]),
|
|
225
|
+
value: unwrapStepValue(selectLooseMatch[1])
|
|
189
226
|
};
|
|
190
227
|
}
|
|
191
228
|
const selectWithoutValueMatch = s.match(/\b(?:select|choose|pick)\s+(.+?)\s+(?:dropdown|combobox|select|menu)\b/i);
|
|
@@ -236,7 +273,8 @@ function extractStepVars(steps, stepHints, assertionHints, overrides) {
|
|
|
236
273
|
const shouldDeclareVariable = binding.kind === "select" || templateEnvKey !== void 0 || overrideValue !== void 0 || hasRuntimeEnvValue;
|
|
237
274
|
let stepVar = shouldDeclareVariable ? seen.get(envKey) : void 0;
|
|
238
275
|
if (shouldDeclareVariable && !stepVar) {
|
|
239
|
-
const
|
|
276
|
+
const placeholderFallback = binding.kind === "fill" ? buildFillPlaceholder(binding.rawField, binding.fieldLabel, selectorTarget) : assertionFallback ?? "option";
|
|
277
|
+
const fallback = overrideValue ?? process.env[envKey] ?? (templateEnvKey ? assertionFallback ?? placeholderFallback : (!fallbackFromBinding || isGenericFallbackValue(fallbackFromBinding)) && assertionFallback ? assertionFallback : fallbackFromBinding) ?? placeholderFallback;
|
|
240
278
|
stepVar = {
|
|
241
279
|
envKey,
|
|
242
280
|
constName: envKey,
|
|
@@ -306,6 +344,33 @@ function ensureStatement(value) {
|
|
|
306
344
|
if (!trimmed) return trimmed;
|
|
307
345
|
return trimmed.endsWith(";") ? trimmed : `${trimmed};`;
|
|
308
346
|
}
|
|
347
|
+
function phraseToRegexPattern(value) {
|
|
348
|
+
return value.trim().split(/\s+/).filter(Boolean).map((token) => escapeForRegex(token)).join("\\s+");
|
|
349
|
+
}
|
|
350
|
+
function buttonNameExpressionFromStep(step) {
|
|
351
|
+
const quotedMatch = step.match(/["']([^"']+)["']/);
|
|
352
|
+
if (quotedMatch) return `'${escapeForSingleQuotedString(quotedMatch[1])}'`;
|
|
353
|
+
const label = step.replace(/^(click|press|tap)\s+(?:on\s+)?(?:the\s+)?/i, "").replace(/\b(button|btn)\b/gi, "").replace(/[.?!,:;]+$/g, "").trim();
|
|
354
|
+
if (!label) return `'button'`;
|
|
355
|
+
const lowered = label.toLowerCase();
|
|
356
|
+
const variants = /* @__PURE__ */ new Set();
|
|
357
|
+
if (/\b(?:login|log in|sign in|sign-in)\b/.test(lowered)) {
|
|
358
|
+
variants.add("login");
|
|
359
|
+
variants.add("log in");
|
|
360
|
+
variants.add("sign in");
|
|
361
|
+
} else if (/\b(?:register|sign up|sign-up|signup|create account)\b/.test(lowered)) {
|
|
362
|
+
variants.add("register");
|
|
363
|
+
variants.add("sign up");
|
|
364
|
+
variants.add("create account");
|
|
365
|
+
} else if (/\bcontinue\b/.test(lowered)) {
|
|
366
|
+
variants.add("continue");
|
|
367
|
+
variants.add("next");
|
|
368
|
+
} else {
|
|
369
|
+
variants.add(label);
|
|
370
|
+
}
|
|
371
|
+
const pattern = Array.from(variants).map(phraseToRegexPattern).join("|");
|
|
372
|
+
return `/${pattern}/i`;
|
|
373
|
+
}
|
|
309
374
|
function parseValueAssertionHint(playwright) {
|
|
310
375
|
const statement = ensureStatement(String(playwright ?? "").trim());
|
|
311
376
|
if (!statement) return void 0;
|
|
@@ -350,9 +415,7 @@ function stepToPlaywright(step, url, hint, stepVar) {
|
|
|
350
415
|
}
|
|
351
416
|
if (/\bclick\b.*(button|btn|submit|sign in|log in|login|register|continue|next|save|confirm)/i.test(s)) {
|
|
352
417
|
if (hintedSelector) return `await ${hintedSelector}.click();`;
|
|
353
|
-
|
|
354
|
-
const name = nameMatch?.[1] ?? s.replace(/click\s+(the\s+)?/i, "").trim();
|
|
355
|
-
return `await page.getByRole('button', { name: '${escapeForSingleQuotedString(name)}' }).click();`;
|
|
418
|
+
return `await page.getByRole('button', { name: ${buttonNameExpressionFromStep(s)} }).click();`;
|
|
356
419
|
}
|
|
357
420
|
if (/\bclick\b.*(link|anchor|nav)/i.test(s)) {
|
|
358
421
|
if (hintedSelector) return `await ${hintedSelector}.click();`;
|
|
@@ -666,4 +729,4 @@ export {
|
|
|
666
729
|
gen,
|
|
667
730
|
genCmd
|
|
668
731
|
};
|
|
669
|
-
//# sourceMappingURL=chunk-
|
|
732
|
+
//# sourceMappingURL=chunk-PYKYHIO3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/gen.ts"],"sourcesContent":["import { Command } from 'commander';\nimport fg from 'fast-glob';\nimport { readFileSync, mkdirSync, writeFileSync, existsSync } from 'node:fs';\nimport { join, basename, relative, resolve } from 'node:path';\n\ntype NormalizedCase = {\n id?: string;\n title: string;\n tags?: string[];\n steps?: string[];\n step_hints?: Array<{ selector?: string }>;\n expected?: string[];\n assertion_hints?: Array<{ playwright?: string }>;\n needs_review?: boolean;\n review_reasons?: string[];\n source?: string;\n url?: string;\n};\n\ntype VarsOverrideMap = Map<string, string>;\n\ntype StepBinding = {\n kind: 'fill' | 'select';\n rawField?: string;\n fieldLabel?: string;\n value?: string;\n};\n\ntype StepVar = {\n envKey: string;\n constName: string;\n fallback: string;\n selectorHint?: string;\n selectorTarget?: string;\n fieldLabel?: string;\n};\n\ntype StepValueState = {\n declarations: StepVar[];\n byStepIndex: Map<number, StepVar>;\n fillValueBySelector: Map<string, string>;\n};\n\nfunction escapeForSingleQuotedString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nfunction escapeForRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\\\/]/g, '\\\\$&');\n}\n\nfunction normalizeUrlForComparison(value?: string): string | undefined {\n if (!value) return undefined;\n try {\n return new URL(value).toString().replace(/\\/$/, '');\n } catch {\n return value.trim().replace(/\\/$/, '');\n }\n}\n\nfunction urlPatternFromAbsoluteUrl(value?: string): string | undefined {\n if (!value) return undefined;\n try {\n const parsed = new URL(value);\n const normalizedPath = `${parsed.pathname}${parsed.search}`.replace(/\\/$/, '') || '/';\n if (normalizedPath === '/') return '\\\\/';\n return normalizedPath.replace(/^\\/+/, '').split('/').map(escapeForRegex).join('\\\\/');\n } catch {\n return undefined;\n }\n}\n\nfunction pageNameToUrlPattern(value: string): string | undefined {\n const cleaned = value\n .replace(/\\b(the|a|an|user)\\b/gi, ' ')\n .replace(/\\b(page|screen)\\b/gi, ' ')\n .trim();\n const tokens = cleaned.split(/[\\s/-]+/).map(token => token.trim()).filter(Boolean);\n if (tokens.length === 0) return undefined;\n return tokens.map(token => escapeForRegex(token.toLowerCase())).join('[-_\\\\/]?');\n}\n\nfunction fieldNameFromSentence(value: string): string | undefined {\n const match =\n value.match(/\\bfor\\s+([a-zA-Z][a-zA-Z\\s-]{0,30}?)\\s+field\\b/i) ??\n value.match(/\\b([a-zA-Z][a-zA-Z\\s-]{0,30}?)\\s+field\\b/i) ??\n value.match(/\\b([a-zA-Z][a-zA-Z\\s-]{0,30}?)\\s+input\\b/i);\n return match?.[1]?.trim();\n}\n\nfunction visibleTextRegexFromPhrase(value: string): string {\n const cleaned = value\n .replace(/[\"']/g, '')\n .replace(/\\b(the|a|an|user|should|must|is|are|be|visible|shown|showing|displayed|present|appears?|rendered)\\b/gi, ' ')\n .replace(/\\b(message|text|content|heading|label)\\b/gi, ' ')\n .trim();\n const tokens = cleaned.split(/\\s+/).filter(Boolean);\n if (tokens.length === 0) return '.+';\n return tokens.map(token => escapeForRegex(token)).join('\\\\s+');\n}\n\nfunction sanitizeEnvSegment(value: string): string {\n return value\n .toUpperCase()\n .replace(/[^A-Z0-9]+/g, '_')\n .replace(/_+/g, '_')\n .replace(/^_|_$/g, '');\n}\n\nfunction normalizeOverrideKey(value: string): string {\n return sanitizeEnvSegment(value.replace(/^CT_VAR_/i, ''));\n}\n\nfunction cleanFieldLabel(value?: string): string | undefined {\n if (!value) return undefined;\n const cleaned = value\n .replace(/[.?!,:;]+$/g, '')\n .replace(/^(?:the|a|an)\\s+/i, '')\n .replace(/\\s+(?:field|input|box|area|dropdown|combobox|select|menu)\\b/gi, '')\n .trim();\n return cleaned || undefined;\n}\n\nfunction isPositionalFieldReference(value?: string): boolean {\n if (!value) return false;\n const cleaned = value.trim().toLowerCase();\n return /^(?:(?:the|a|an)\\s+)?(?:first|second|third|fourth|fifth|sixth|seventh|eighth|ninth|tenth|\\d+(?:st|nd|rd|th)?)(?:\\s+\\w+){0,2}\\s+(?:field|input|box|area|dropdown|combobox|select|menu)$/.test(cleaned);\n}\n\nfunction fieldNameToEnvSuffix(value?: string): string | undefined {\n if (!value || isPositionalFieldReference(value)) return undefined;\n const cleaned = value\n .replace(/[.?!,:;]+$/g, '')\n .replace(/^(?:the|a|an)\\s+/i, '')\n .replace(/\\b(?:field|input|box|area|dropdown|combobox|select|menu)\\b/gi, ' ')\n .trim();\n const suffix = sanitizeEnvSegment(cleaned);\n if (!suffix) return undefined;\n if (/^(?:FIELD|INPUT|BOX|AREA|DROPDOWN|COMBOBOX|SELECT|MENU)$/.test(suffix)) return undefined;\n return suffix;\n}\n\nfunction normalizeSelectorTarget(value?: string): string | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n return trimmed.replace(/^page\\./, '').replace(/\\s+/g, ' ');\n}\n\nfunction parseQuotedLiteral(value?: string): string | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (trimmed.length < 2) return undefined;\n\n if (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n try {\n return JSON.parse(trimmed);\n } catch {\n return trimmed.slice(1, -1);\n }\n }\n\n if (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")) {\n return trimmed\n .slice(1, -1)\n .replace(/\\\\\\\\/g, '\\\\')\n .replace(/\\\\'/g, \"'\");\n }\n\n return undefined;\n}\n\nfunction 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 resolveStepVarOverride(\n overrides: VarsOverrideMap,\n envKey: string,\n keySuffix: string,\n rawField?: string,\n fieldLabel?: string,\n): string | undefined {\n const candidates = [envKey, keySuffix, rawField, fieldLabel];\n for (const candidate of candidates) {\n if (!candidate) continue;\n const normalized = normalizeOverrideKey(candidate);\n if (normalized && overrides.has(normalized)) return overrides.get(normalized);\n }\n return undefined;\n}\n\nfunction extractStepVars(\n steps: string[],\n stepHints: Array<{ selector?: string }> | undefined,\n assertionHints: Array<{ playwright?: string }> | undefined,\n overrides: VarsOverrideMap,\n): StepValueState {\n const declarations: StepVar[] = [];\n const byStepIndex = new Map<number, StepVar>();\n const fillValueBySelector = new Map<string, string>();\n const seen = new Map<string, StepVar>();\n let unnamedFillIndex = 0;\n let unnamedSelectIndex = 0;\n\n const assertionFallbacks = new Map<string, string>();\n for (const hint of assertionHints ?? []) {\n const parsed = parseValueAssertionHint(hint?.playwright);\n if (!parsed?.expected) continue;\n if (parsed.target) assertionFallbacks.set(parsed.target, parsed.expected);\n const envSuffix = selectorTargetToEnvSuffix(parsed.target);\n if (envSuffix) assertionFallbacks.set(`CT_VAR_${envSuffix}`, parsed.expected);\n }\n\n for (const [index, step] of steps.entries()) {\n const binding = parseStepBinding(step);\n if (!binding) continue;\n\n const selectorTarget = normalizeSelectorTarget(stepHints?.[index]?.selector);\n const keySuffix =\n fieldNameToEnvSuffix(binding.rawField) ??\n fieldNameToEnvSuffix(binding.fieldLabel) ??\n selectorTargetToEnvSuffix(selectorTarget) ??\n `${binding.kind === 'select' ? 'SELECT' : 'INPUT'}_${binding.kind === 'select' ? ++unnamedSelectIndex : ++unnamedFillIndex}`;\n const templateEnvKey = extractCtVarTemplate(binding.value);\n const envKey = templateEnvKey ?? `CT_VAR_${keySuffix}`;\n const assertionFallback =\n (selectorTarget ? assertionFallbacks.get(selectorTarget) : undefined) ??\n assertionFallbacks.get(envKey);\n const overrideValue = resolveStepVarOverride(overrides, envKey, keySuffix, binding.rawField, binding.fieldLabel);\n const fallbackFromBinding = binding.value?.trim();\n const hasRuntimeEnvValue = process.env[envKey] !== undefined;\n const shouldDeclareVariable =\n binding.kind === 'select' ||\n templateEnvKey !== undefined ||\n overrideValue !== undefined ||\n hasRuntimeEnvValue;\n\n let stepVar = shouldDeclareVariable ? seen.get(envKey) : undefined;\n if (shouldDeclareVariable && !stepVar) {\n const 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 pageMatch = s.match(/\\b(?:remains?|stays?|still)\\s+on\\s+(?:the\\s+)?(.+?)(?:\\s+page|\\s+screen)?$/i);\n const pagePattern = pageMatch?.[1] ? pageNameToUrlPattern(pageMatch[1]) : undefined;\n return `await expect(page).toHaveURL(/${pagePattern || currentUrlPattern || 'login'}/);`;\n }\n\n // URL / redirect check\n if (/\\b(url|redirect(?:s|ed)?|navigate(?:s|d)?|route|path)\\b/i.test(s)) {\n const pathMatch =\n s.match(/[\"'](\\/[^\"']+)[\"']/) ??\n s.match(/to\\s+(\\/[\\w/-]+)/i) ??\n s.match(/https?:\\/\\/[^\\s'\"]+/i);\n const matchedPath = pathMatch?.[1] ?? pathMatch?.[0];\n if (matchedPath) {\n const fromUrl = matchedPath.startsWith('http') ? urlPatternFromAbsoluteUrl(matchedPath) : undefined;\n const directPath = matchedPath.startsWith('/') ? matchedPath.replace(/^\\/+/, '').split('/').map(escapeForRegex).join('\\\\/') : undefined;\n const finalPattern = fromUrl ?? directPath ?? currentUrlPattern;\n if (finalPattern !== undefined) return `await expect(page).toHaveURL(/${finalPattern}/);`;\n }\n return `await expect(page).toHaveURL(/dashboard|success|home/);`;\n }\n\n // Page title\n if (/\\bpage title\\b|\\btitle should\\b|\\bdocument title\\b/i.test(s)) {\n const titleMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (titleMatch) return `await expect(page).toHaveTitle('${escapeForSingleQuotedString(titleMatch[1])}');`;\n return `await expect(page).toHaveTitle(/.+/);`;\n }\n\n // Error / validation message\n if (/\\b(error|invalid|fail|incorrect|required|validation)\\b/i.test(s)) {\n const msgMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (msgMatch) return `await expect(page.getByText('${escapeForSingleQuotedString(msgMatch[1])}')).toBeVisible();`;\n if (fieldName) return `await expect(page.getByText(/${escapeForRegex(fieldName)}/i)).toBeVisible();`;\n return `await expect(page.getByRole('alert')).toBeVisible();`;\n }\n\n // Success / confirmation\n if (/\\b(success|confirm|complete|thank|welcome|sent|saved)\\b/i.test(s)) {\n const msgMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (msgMatch) return `await expect(page.getByText('${escapeForSingleQuotedString(msgMatch[1])}')).toBeVisible();`;\n if (/\\bwelcome\\b/i.test(s)) return `await expect(page.getByText(/welcome/i)).toBeVisible();`;\n return `await expect(page.getByRole('status')).toBeVisible();`;\n }\n\n // Not visible / hidden\n if (/\\b(not visible|hidden|disappear|removed|gone)\\b/i.test(s)) {\n const elementMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (elementMatch) return `await expect(page.getByText('${escapeForSingleQuotedString(elementMatch[1])}')).not.toBeVisible();`;\n return `await expect(page.locator('.modal, [role=\"dialog\"]').first()).not.toBeVisible();`;\n }\n\n // Visible / present\n if (/\\b(visible|appear|display|show|render|present)\\b/i.test(s)) {\n const elementMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (elementMatch) return `await expect(page.getByText('${escapeForSingleQuotedString(elementMatch[1])}')).toBeVisible();`;\n const subjectMatch =\n s.match(/^(?:the\\s+)?(.+?)\\s+(?:is|are|should|must|becomes?|appears?|renders?|shows?|displays?)\\b/i) ??\n s.match(/^(?:the\\s+)?(.+?)\\s+(?:visible|present)\\b/i);\n const subject = subjectMatch?.[1]?.trim();\n if (subject) {\n if (/\\bnavigation\\b.*\\bmenu\\b|\\bmenu\\b.*\\bnavigation\\b|\\bnavigation\\b/i.test(subject)) {\n return `await expect(page.getByRole('navigation')).toBeVisible();`;\n }\n return `await expect(page.getByText(/${visibleTextRegexFromPhrase(subject)}/i)).toBeVisible();`;\n }\n return `await expect(page.locator('[data-testid]').first()).toBeVisible();`;\n }\n\n // Count of items\n if (/\\b(count|number of|list of|\\d+\\s+item)\\b/i.test(s)) {\n const countMatch = s.match(/(\\d+)/);\n if (countMatch) return `await expect(page.locator('li, tr, [role=\"listitem\"]')).toHaveCount(${countMatch[1]});`;\n return `await expect(page.locator('li, tr').first()).toBeVisible();`;\n }\n\n // Enabled / disabled\n if (/\\b(enabled|clickable|active)\\b/i.test(s)) {\n return `await expect(page.getByRole('button').first()).toBeEnabled();`;\n }\n if (/\\b(disabled|inactive)\\b/i.test(s)) {\n return `await expect(page.getByRole('button').first()).toBeDisabled();`;\n }\n\n // Input value\n if (/\\b(clear|cleared|empty|blank)\\b/i.test(s) && /\\b(field|input|value)\\b/i.test(s)) {\n return `await expect(page.getByRole('textbox').first()).toHaveValue('');`;\n }\n if (/\\b(field|input|value|filled)\\b/i.test(s)) {\n const valMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (valMatch) {\n const envSuffix = fieldNameToEnvSuffix(fieldName);\n const stepVar = envSuffix ? stepState?.declarations.find(candidate => candidate.envKey === `CT_VAR_${envSuffix}`) : undefined;\n if (stepVar) return `await expect(page.getByRole('textbox').first()).toHaveValue(${stepVar.constName});`;\n return `await expect(page.getByRole('textbox').first()).toHaveValue('${escapeForSingleQuotedString(valMatch[1])}');`;\n }\n return `await expect(page.getByRole('textbox').first()).not.toBeEmpty();`;\n }\n\n // Text / heading / content (broad fallback before final fallback)\n if (/\\b(text|content|label|message|heading)\\b/i.test(s)) {\n const textMatch = s.match(/[\"']([^\"']+)[\"']/);\n if (textMatch) return `await expect(page.getByText('${escapeForSingleQuotedString(textMatch[1])}')).toBeVisible();`;\n const words = s.replace(/\\b(the|should|must|contain|display|show|have|text|content)\\b/gi, '').trim();\n return `await expect(page.getByText(/${visibleTextRegexFromPhrase(words)}/i)).toBeVisible();`;\n }\n\n // Final fallback\n const cleaned = s.replace(/[\"']/g, '').trim();\n return `await expect(page.getByText(/${visibleTextRegexFromPhrase(cleaned)}/i)).toBeVisible(); // TODO: refine assertion`;\n}\n\n// ─── POM class name / filename ────────────────────────────────────────────────\n\nfunction toIdentifier(value: string, fallback = 'Landing'): string {\n const tokens = value\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .split(/[^a-zA-Z0-9_]+/)\n .filter(Boolean);\n\n const identifier = tokens\n .map((token) => {\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 = norm.steps ?? [];\n const expected = norm.expected ?? [];\n const stepVars = extractStepVars(steps, norm.step_hints, norm.assertion_hints, overrides);\n\n let importPath = pomImportPath.replace(/\\\\/g, '/');\n if (!importPath.startsWith('.')) importPath = `./${importPath}`;\n // Strip .ts extension — TypeScript resolves without it\n importPath = importPath.replace(/\\.ts$/, '');\n\n const stepLines = steps.length\n ? steps\n .map((s, index) => ` ${stepToPlaywright(s, norm.url, norm.step_hints?.[index], stepVars.byStepIndex.get(index))}`)\n .join('\\n')\n : ' // TODO: add steps';\n\n const assertionLines = expected.length\n ? expected.map((e, index) => ` ${expectedToAssertion(e, norm, norm.assertion_hints?.[index], stepVars)}`).join('\\n')\n : ' // TODO: add assertions';\n\n const reviewNote = norm.needs_review\n ? `\\n // ⚠️ Flagged for review — steps or assertions may need manual refinement\\n`\n : '';\n const variableHeader = buildVariableHeaderComment(stepVars.declarations);\n const variableHeaderBlock = variableHeader ? `${variableHeader}\\n` : '';\n const variableDeclarations = buildVariableDeclarations(stepVars.declarations);\n\n return `import { test, expect } from '@playwright/test';\nimport { ${pomClassName} } from '${importPath}';\n\n${variableHeaderBlock}test('${title}', async ({ page }) => {${reviewNote}\n const pomPage = new ${pomClassName}(page);\n\n${variableDeclarations} // ── Setup ─────────────────────────────────────────────────────────────────\n await pomPage.goto();\n await pomPage.waitForLoad();\n\n // ── Steps ─────────────────────────────────────────────────────────────────\n${stepLines}\n\n // ── Assertions ────────────────────────────────────────────────────────────\n${assertionLines}\n});\n`;\n}\n\n// ─── Main ─────────────────────────────────────────────────────────────────────\n\nexport async function gen(opts: { lang: string; out: string; vars?: string }) {\n if (opts.lang !== 'ts' && opts.lang !== 'js') {\n console.error('❌ --lang must be ts or js');\n process.exit(1);\n }\n const lang = opts.lang as 'ts' | 'js';\n const specExt = lang === 'js' ? 'spec.js' : 'spec.ts';\n const pomExt = lang === 'js' ? '.js' : '.ts';\n const varsOverride = parseVarsOverride(opts.vars);\n\n const normalized = await fg([\n '.cementic/normalized/*.json',\n '!.cementic/normalized/_index.json',\n ]);\n\n if (normalized.length === 0) {\n console.warn('⚠️ No normalized cases found in .cementic/normalized/');\n console.warn(' Run: ct normalize ./cases');\n process.exit(1);\n }\n\n const projectRoot = process.cwd();\n const testsOutDir = resolve(projectRoot, opts.out);\n const pagesOutDir = resolve(projectRoot, 'pages');\n\n mkdirSync(testsOutDir, { recursive: true });\n mkdirSync(pagesOutDir, { recursive: true });\n\n let specCount = 0;\n let pomCount = 0;\n\n for (const f of normalized) {\n const norm = JSON.parse(readFileSync(f, 'utf8')) as NormalizedCase;\n\n const pomClassName = derivePomClassName(norm);\n const pomFileName = pomClassName + pomExt;\n const pomFilePath = join(pagesOutDir, pomFileName);\n\n // Only write a POM file if one doesn't exist yet — never overwrite user edits\n if (!existsSync(pomFilePath)) {\n writeFileSync(pomFilePath, buildPomClass(pomClassName, norm, lang));\n pomCount++;\n }\n\n // Relative import from the test file location to the POM file\n const relToPages = relative(testsOutDir, pagesOutDir);\n const pomImportPath = join(relToPages, pomFileName);\n\n const stem = basename(f).replace(/\\.json$/, '').replace(/[^\\w-]+/g, '-');\n const specPath = join(testsOutDir, `${stem}.${specExt}`);\n writeFileSync(specPath, buildSpecFile(norm, pomClassName, pomImportPath, varsOverride));\n specCount++;\n }\n\n console.log(`✅ Generated ${specCount} spec file(s) → ${opts.out}/`);\n if (pomCount > 0) {\n console.log(`✅ Generated ${pomCount} POM class file(s) → pages/`);\n }\n if (pomCount === 0 && specCount > 0) {\n console.log(`ℹ️ POM classes already exist — skipped regeneration`);\n }\n}\n\nexport function genCmd() {\n const cmd = new Command('gen')\n .description('Generate Playwright POM spec + page-object files from normalized cases')\n .addHelpText('after', `\nExamples:\n $ ct gen --lang ts\n $ ct gen --lang js --out tests/e2e\n $ ct gen --lang ts --vars '{\"email\":\"admin@example.com\"}'\n`)\n .option('--lang <lang>', 'Target language (ts|js)', 'ts')\n .option('--out <dir>', 'Output directory for spec files', 'tests/generated')\n .option('--vars <json>', 'JSON object of fallback values for generated CT_VAR_* constants')\n .action(async opts => {\n await gen({ lang: opts.lang, out: opts.out, vars: opts.vars });\n });\n return cmd;\n}\n"],"mappings":"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","names":[]}
|