@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.
@@ -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
- const value = valueMap[key] || "Test Value";
152
- console.log(` ⌨️ Multi-fill: "${field}" "${value}"`);
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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cutleryapp/agent",
3
- "version": "1.0.30",
3
+ "version": "1.0.32",
4
4
  "description": "Local agent that connects your machine to the Cutlery QA platform and runs UI tests via Playwright",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {