@cutleryapp/agent 1.0.30 → 1.0.32
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 +61 -2
- package/package.json +1 -1
package/dist/mcp-executor.js
CHANGED
|
@@ -148,8 +148,12 @@ class TestExecutor {
|
|
|
148
148
|
};
|
|
149
149
|
for (const field of fields) {
|
|
150
150
|
const key = field.toLowerCase().replace(/[\s_-]+/g, "");
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
// Test data first, then AI default map, then fallback
|
|
152
|
+
const dataValue = varMap[field] ?? varMap[key] ??
|
|
153
|
+
Object.entries(varMap).find(([k]) => k.toLowerCase().replace(/[\s_-]+/g, "") === key)?.[1];
|
|
154
|
+
const value = dataValue ?? valueMap[key] ?? "Test Value";
|
|
155
|
+
const src = dataValue ? "test data" : "AI default";
|
|
156
|
+
console.log(` ⌨️ Multi-fill: "${field}" → "${value}" (${src})`);
|
|
153
157
|
try {
|
|
154
158
|
await tryFill(page, field, value);
|
|
155
159
|
}
|
|
@@ -701,6 +705,57 @@ async function tryAIClick(page, selector) {
|
|
|
701
705
|
}
|
|
702
706
|
return false;
|
|
703
707
|
}
|
|
708
|
+
/** Fill an autocomplete/typeahead input: type value, wait for dropdown, click first matching option */
|
|
709
|
+
async function tryAutocomplete(page, labelOrSelector, value) {
|
|
710
|
+
const TIMEOUT = 4000;
|
|
711
|
+
const locators = [
|
|
712
|
+
page.getByLabel(new RegExp(labelOrSelector, 'i')),
|
|
713
|
+
page.getByPlaceholder(new RegExp(labelOrSelector, 'i')),
|
|
714
|
+
page.locator(labelOrSelector),
|
|
715
|
+
];
|
|
716
|
+
for (const loc of locators) {
|
|
717
|
+
try {
|
|
718
|
+
const input = loc.first();
|
|
719
|
+
await input.waitFor({ state: 'visible', timeout: TIMEOUT });
|
|
720
|
+
await input.click({ timeout: TIMEOUT });
|
|
721
|
+
await input.fill('', { timeout: TIMEOUT });
|
|
722
|
+
// Type slowly so the autocomplete can react
|
|
723
|
+
await input.type(value, { delay: 80 });
|
|
724
|
+
// Wait for dropdown options to appear
|
|
725
|
+
await page.waitForTimeout(600);
|
|
726
|
+
// Try common dropdown option selectors
|
|
727
|
+
const optionSelectors = [
|
|
728
|
+
`[class*="option"]:has-text("${value}")`,
|
|
729
|
+
`[class*="suggestion"]:has-text("${value}")`,
|
|
730
|
+
`[class*="item"]:has-text("${value}")`,
|
|
731
|
+
`[role="option"]:has-text("${value}")`,
|
|
732
|
+
`[role="listbox"] [class*="option"]`,
|
|
733
|
+
`[class*="menu"] [class*="option"]`,
|
|
734
|
+
`[class*="dropdown"] li`,
|
|
735
|
+
`ul[class*="auto"] li`,
|
|
736
|
+
`.react-select__option`,
|
|
737
|
+
`.autocomplete-item`,
|
|
738
|
+
];
|
|
739
|
+
for (const optSel of optionSelectors) {
|
|
740
|
+
try {
|
|
741
|
+
const opt = page.locator(optSel).first();
|
|
742
|
+
if (await opt.isVisible({ timeout: 800 })) {
|
|
743
|
+
await opt.click({ timeout: TIMEOUT });
|
|
744
|
+
console.log(` ✓ Autocomplete: typed "${value}", clicked option via "${optSel}"`);
|
|
745
|
+
return true;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
catch { /* try next */ }
|
|
749
|
+
}
|
|
750
|
+
// Fallback: press Enter if a highlighted option exists
|
|
751
|
+
await page.keyboard.press('Enter');
|
|
752
|
+
await page.waitForTimeout(300);
|
|
753
|
+
return true;
|
|
754
|
+
}
|
|
755
|
+
catch { /* try next locator */ }
|
|
756
|
+
}
|
|
757
|
+
return false;
|
|
758
|
+
}
|
|
704
759
|
/** Try filling with multiple selector strategies */
|
|
705
760
|
async function tryAIFill(page, selector, value) {
|
|
706
761
|
const TIMEOUT = 5000;
|
|
@@ -900,6 +955,10 @@ async function tryFill(page, label, value) {
|
|
|
900
955
|
errors.push(e?.message?.split("\n")[0] || String(e));
|
|
901
956
|
}
|
|
902
957
|
}
|
|
958
|
+
// Autocomplete fallback — type + wait for dropdown + click option
|
|
959
|
+
const acSuccess = await tryAutocomplete(page, label, value);
|
|
960
|
+
if (acSuccess)
|
|
961
|
+
return;
|
|
903
962
|
// AI vision fallback
|
|
904
963
|
const aiSuccess = await aiFillFallback(page, label, value);
|
|
905
964
|
if (aiSuccess)
|