ccqa 1.40.4 → 1.40.6
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/dist/bin/ccqa.mjs +19 -15
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/bin/ccqa.mjs
CHANGED
|
@@ -1660,7 +1660,7 @@ async function invokeClaudeStreaming(options, onEvent) {
|
|
|
1660
1660
|
};
|
|
1661
1661
|
if (hasRefSelector(cmd)) return {
|
|
1662
1662
|
decision: "block",
|
|
1663
|
-
reason: "@ref selectors (like @e14) are session-specific and change every run. They cannot be used in generated tests. Use one of the allowed selector formats instead: [aria-label='...'], text=..., [placeholder='...'], or [type='password']. Take a fresh snapshot and find the element's aria-label or visible text."
|
|
1663
|
+
reason: "@ref selectors (like @e14) are session-specific and change every run. They cannot be used in generated tests. Use one of the allowed selector formats instead: [aria-label='...'], text=..., [placeholder='...'], or [type='password']. Take a fresh snapshot and find the element's aria-label or visible text. If an allowed selector already clicks the element but nothing happens, the element is clipped by an inner scroll container: `scrollintoview` it (addressed by a CSS selector, not `text=`) and click again — a @ref would not have fixed that either."
|
|
1664
1664
|
};
|
|
1665
1665
|
const bareTag = findPositionalBareTag(cmd);
|
|
1666
1666
|
if (bareTag !== null) return {
|
|
@@ -15204,25 +15204,26 @@ function actionToLine(action) {
|
|
|
15204
15204
|
return `// [warn] replay-unstable: dropped over-assertion (${action.assert ?? "assert"} ${sel}) — selector not present on replay`;
|
|
15205
15205
|
}
|
|
15206
15206
|
const locator = action.locator ? locatorToPlaywright(action.locator, action.index) : null;
|
|
15207
|
+
const subject = locator !== null && action.index === void 0 ? `${locator}.first()` : locator;
|
|
15207
15208
|
switch (action.action) {
|
|
15208
15209
|
case "navigate": return `await page.goto(${jExpr(action.value ?? "")});`;
|
|
15209
|
-
case "click": return
|
|
15210
|
-
case "dblclick": return
|
|
15210
|
+
case "click": return subject ? `await ${subject}.click();` : droppedActionMarker(action);
|
|
15211
|
+
case "dblclick": return subject ? `await ${subject}.dblclick();` : droppedActionMarker(action);
|
|
15211
15212
|
case "fill":
|
|
15212
|
-
case "type": return
|
|
15213
|
-
case "press": return
|
|
15214
|
-
case "check": return
|
|
15215
|
-
case "uncheck": return
|
|
15216
|
-
case "select": return
|
|
15217
|
-
case "hover": return
|
|
15218
|
-
case "focus": return
|
|
15213
|
+
case "type": return subject ? `await ${subject}.fill(${jExpr(action.value ?? "")});` : droppedActionMarker(action);
|
|
15214
|
+
case "press": return subject ? `await ${subject}.press(${jExpr(action.value ?? "")});` : `await page.keyboard.press(${jExpr(action.value ?? "")});`;
|
|
15215
|
+
case "check": return subject ? `await ${subject}.check();` : droppedActionMarker(action);
|
|
15216
|
+
case "uncheck": return subject ? `await ${subject}.uncheck();` : droppedActionMarker(action);
|
|
15217
|
+
case "select": return subject ? `await ${subject}.selectOption(${jExpr(action.value ?? "")});` : droppedActionMarker(action);
|
|
15218
|
+
case "hover": return subject ? `await ${subject}.hover();` : droppedActionMarker(action);
|
|
15219
|
+
case "focus": return subject ? `await ${subject}.focus();` : droppedActionMarker(action);
|
|
15219
15220
|
case "drag":
|
|
15220
|
-
if (!
|
|
15221
|
-
return `await ${
|
|
15221
|
+
if (!subject || !action.target) return droppedActionMarker(action);
|
|
15222
|
+
return `await ${subject}.dragTo(${locatorToPlaywright(action.target)}.first());`;
|
|
15222
15223
|
case "upload": {
|
|
15223
15224
|
const files = action.files ?? [];
|
|
15224
|
-
if (!
|
|
15225
|
-
return `await ${
|
|
15225
|
+
if (!subject || files.length === 0) return droppedActionMarker(action);
|
|
15226
|
+
return `await ${subject}.setInputFiles([${files.map(jExpr).join(", ")}]);`;
|
|
15226
15227
|
}
|
|
15227
15228
|
case "scroll": return scrollToLine(action);
|
|
15228
15229
|
case "wait": return waitToLine(action, locator);
|
|
@@ -17808,12 +17809,14 @@ find nth <index> "<ALLOWED-css>" <action>
|
|
|
17808
17809
|
3. \`find last\` is reliable only when the layout guarantees "the target is the bottom-most match" (e.g. the most-recently-sent chat message). Be explicit in the AB_ACTION label.
|
|
17809
17810
|
4. Argument order is \`<value> <action> [flags]\` — flags after the action. Putting \`--name\` / \`--exact\` before the action makes agent-browser fail with "Unknown subaction".
|
|
17810
17811
|
5. \`--name "<n>"\` is **role-only**. Never pass it to \`find text\`, \`find label\`, etc.
|
|
17811
|
-
6. \`
|
|
17812
|
+
6. \`--name\` matches by substring. Add \`--exact\` whenever the name you read from the snapshot is the element's whole accessible name — without it a short name such as "Log in" also matches "Log in with Google" and "Log in with SSO", and the recording silently pins the first of them.
|
|
17813
|
+
7. \`find\` includes its own wait; do not chain a \`wait\` before it.
|
|
17812
17814
|
|
|
17813
17815
|
**Examples:**
|
|
17814
17816
|
|
|
17815
17817
|
- ✓ \`find last "[data-testid='reply-link']" click\` — specific attribute + layout-guaranteed last match
|
|
17816
17818
|
- ✓ \`find role button click --name "Submit"\` — role + accessible name (flags after action)
|
|
17819
|
+
- ✓ \`find role button click --name "Log in" --exact\` — short name needs \`--exact\`, or "Log in with SSO" matches too
|
|
17817
17820
|
- ✗ \`find role button --name "Submit" click\` — wrong order
|
|
17818
17821
|
- ✗ \`find last "button" click\` — bare tag
|
|
17819
17822
|
|
|
@@ -17826,6 +17829,7 @@ find nth <index> "<ALLOWED-css>" <action>
|
|
|
17826
17829
|
5. For checkboxes: try \`check "text=Label"\` or \`check "[aria-label='Label']"\`.
|
|
17827
17830
|
6. If repeated labels make every ALLOWED selector ambiguous → use the \`find\` subset above.
|
|
17828
17831
|
7. Never guess. If a selector fails, take a fresh snapshot before retrying.
|
|
17832
|
+
8. **A click that reports success but changes nothing means the element sits outside the visible part of an inner scroll container** — the event dispatches, the app never reacts, and no error is printed. Run \`scrollintoview\` on the element and click again. Scroll to the element itself, addressed by a CSS selector (\`scrollintoview "button.primary-action"\`); \`scrollintoview "text=…"\` can land on a text node that leaves the control still clipped. Do not read this as a product bug or reach for a \`@ref\` — verify by checking that the DOM changed (e.g. \`get count\` on what the click should have produced).
|
|
17829
17833
|
|
|
17830
17834
|
### Special input types
|
|
17831
17835
|
|
package/dist/package.json
CHANGED