@cutleryapp/agent 1.0.44 → 1.0.45
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/mcp-executor.js +34 -17
- package/package.json +1 -1
package/dist/mcp-executor.js
CHANGED
|
@@ -85,9 +85,14 @@ class TestExecutor {
|
|
|
85
85
|
const stepAttachment = (testCase.step_attachments || {})[String(i)] || null;
|
|
86
86
|
console.log(` 📎 Step ${i} attachment: ${stepAttachment ? `YES (${stepAttachment.length} chars)` : 'none'}`);
|
|
87
87
|
let stepError;
|
|
88
|
-
// Dismiss any open overlay (
|
|
89
|
-
if (i > 0)
|
|
88
|
+
// Dismiss any open overlay (calendar, dropdown, modal) left from the previous step
|
|
89
|
+
if (i > 0) {
|
|
90
90
|
await page.keyboard.press('Escape').catch(() => { });
|
|
91
|
+
await page.waitForTimeout(80);
|
|
92
|
+
// Click a neutral spot (top-left corner) to blur active element and close popups
|
|
93
|
+
await page.mouse.click(10, 10).catch(() => { });
|
|
94
|
+
await page.waitForTimeout(80);
|
|
95
|
+
}
|
|
91
96
|
try {
|
|
92
97
|
// When a reference image is attached, skip MCP strategies entirely and go
|
|
93
98
|
// straight to the AI multi-field loop so it can scan the form and fill everything.
|
|
@@ -387,21 +392,29 @@ class TestExecutor {
|
|
|
387
392
|
catch { /* next */ }
|
|
388
393
|
}
|
|
389
394
|
}
|
|
390
|
-
// 2. Radio / checkbox
|
|
391
|
-
// are handled in <100ms instead of waiting through autocomplete timeouts
|
|
395
|
+
// 2. Radio / checkbox — try before autocomplete so radios resolve in <100ms
|
|
392
396
|
if (!selHandled) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
397
|
+
for (const sel of [
|
|
398
|
+
`label:text-is("${optionValue}")`, // exact case-insensitive
|
|
399
|
+
`label:has-text("${optionValue}")`, // substring match
|
|
400
|
+
`[role="radio"]:has-text("${optionValue}")`,
|
|
401
|
+
`input[type="radio"][value="${optionValue}" i]`,
|
|
402
|
+
`input[type="checkbox"][value="${optionValue}" i]`,
|
|
403
|
+
]) {
|
|
404
|
+
try {
|
|
405
|
+
const loc = page.locator(sel).first();
|
|
406
|
+
const tag = await loc.evaluate((el) => el.tagName.toLowerCase()).catch(() => 'label');
|
|
407
|
+
if (tag === 'input') {
|
|
408
|
+
await loc.click({ force: true, timeout: 800 });
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
await loc.click({ timeout: 800 });
|
|
412
|
+
}
|
|
413
|
+
selHandled = true;
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
catch { /* try next */ }
|
|
403
417
|
}
|
|
404
|
-
catch { /* not an input with matching value */ }
|
|
405
418
|
}
|
|
406
419
|
// 3. React-select / autocomplete typeahead
|
|
407
420
|
if (!selHandled) {
|
|
@@ -1268,11 +1281,15 @@ async function tryFillDate(page, label, value) {
|
|
|
1268
1281
|
await page.keyboard.press('Meta+a'); // Mac
|
|
1269
1282
|
await page.keyboard.type(value, { delay: 40 });
|
|
1270
1283
|
await page.waitForTimeout(150);
|
|
1271
|
-
// Tab out to commit
|
|
1284
|
+
// Tab out to commit and close the calendar
|
|
1272
1285
|
await page.keyboard.press('Tab');
|
|
1273
1286
|
await page.waitForTimeout(200);
|
|
1274
|
-
//
|
|
1287
|
+
// Aggressively close any calendar still open
|
|
1275
1288
|
await page.keyboard.press('Escape').catch(() => { });
|
|
1289
|
+
await page.waitForTimeout(100);
|
|
1290
|
+
// Click neutral area to ensure calendar/overlay is gone
|
|
1291
|
+
await page.mouse.click(10, 10).catch(() => { });
|
|
1292
|
+
await page.waitForTimeout(150);
|
|
1276
1293
|
return;
|
|
1277
1294
|
}
|
|
1278
1295
|
catch { /* try next */ }
|