@cutleryapp/agent 1.0.34 → 1.0.35

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.
@@ -216,7 +216,7 @@ class TestExecutor {
216
216
  // Try native <select>
217
217
  try {
218
218
  const fieldLoc = page.getByLabel(new RegExp(fieldLabel, 'i')).first();
219
- await fieldLoc.selectOption({ label: optionValue });
219
+ await fieldLoc.selectOption({ label: optionValue }, { timeout: 3000 });
220
220
  selHandled = true;
221
221
  }
222
222
  catch { /* not a native select */ }
@@ -227,7 +227,7 @@ class TestExecutor {
227
227
  // Try clicking a visible option in an already-open dropdown
228
228
  if (!selHandled) {
229
229
  try {
230
- await page.locator(`[role="option"]:has-text("${optionValue}"), [class*="option"]:has-text("${optionValue}")`).first().click({ timeout: 3000 });
230
+ await page.locator(`[role="option"]:has-text("${optionValue}"), [class*="option"]:has-text("${optionValue}")`).first().click({ timeout: 1500 });
231
231
  selHandled = true;
232
232
  }
233
233
  catch { /* fall to AI */ }
@@ -243,12 +243,12 @@ class TestExecutor {
243
243
  const labelText = cbMatch[1].trim();
244
244
  try {
245
245
  // Try label click (works for hidden checkboxes with styled labels)
246
- await page.locator(`label:has-text("${labelText}")`).first().click({ timeout: 3000 });
246
+ await page.locator(`label:has-text("${labelText}")`).first().click({ timeout: 2000 });
247
247
  handled = true;
248
248
  }
249
249
  catch {
250
250
  try {
251
- await page.getByLabel(new RegExp(labelText, 'i')).first().check({ timeout: 3000 });
251
+ await page.getByLabel(new RegExp(labelText, 'i')).first().check({ timeout: 2000 });
252
252
  handled = true;
253
253
  }
254
254
  catch { /* fall to AI */ }
@@ -332,7 +332,7 @@ function extractSelector(step, pattern) {
332
332
  }
333
333
  // Fast probe: try each locator strategy with a short timeout so fallbacks don't stall
334
334
  async function tryClick(page, nameRe, label) {
335
- const FAST = 1500;
335
+ const FAST = 800;
336
336
  const strategies = [
337
337
  () => page.getByRole('button', { name: nameRe }).first().click({ timeout: FAST }),
338
338
  () => page.getByRole('link', { name: nameRe }).first().click({ timeout: FAST }),
@@ -584,7 +584,7 @@ async function aiStepFallback(page, stepText, stepAttachment = null) {
584
584
  console.log(` 🤖 aiStepFallback called. hasAttachment=${!!stepAttachment}`);
585
585
  const { default: OpenAI } = await import('openai');
586
586
  const openai = new OpenAI({ apiKey: openaiKey });
587
- const MAX_ROUNDS = stepAttachment ? 10 : 6;
587
+ const MAX_ROUNDS = stepAttachment ? 6 : 3;
588
588
  let consecutiveFailures = 0;
589
589
  for (let round = 0; round < MAX_ROUNDS; round++) {
590
590
  const domElements = await extractDomElements(page);
@@ -642,9 +642,9 @@ ${domElements}` + (stepAttachment ? `\n\nThe REFERENCE IMAGE (second image) show
642
642
  else if (act.action === 'select') {
643
643
  let done = false;
644
644
  for (const fn of [
645
- () => page.locator(act.selector).first().selectOption({ label: act.value }, { timeout: 4000 }),
646
- () => page.locator(act.selector).first().selectOption({ value: act.value }, { timeout: 4000 }),
647
- async () => { await page.locator(act.selector).first().click({ timeout: 3000 }); await page.getByText(act.value, { exact: false }).first().click({ timeout: 3000 }); },
645
+ () => page.locator(act.selector).first().selectOption({ label: act.value }, { timeout: 2000 }),
646
+ () => page.locator(act.selector).first().selectOption({ value: act.value }, { timeout: 2000 }),
647
+ async () => { await page.locator(act.selector).first().click({ timeout: 2000 }); await page.getByText(act.value, { exact: false }).first().click({ timeout: 2000 }); },
648
648
  ]) {
649
649
  try {
650
650
  await fn();
@@ -664,11 +664,11 @@ ${domElements}` + (stepAttachment ? `\n\nThe REFERENCE IMAGE (second image) show
664
664
  // Derive a label text from selector for label-based fallbacks
665
665
  const labelHint = act.label || act.selector.replace(/[#.\[\]"'=*^$]/g, ' ').trim();
666
666
  for (const fn of [
667
- () => el.click({ force: true, timeout: 4000 }), // force bypasses visibility
668
- () => el.check({ force: true, timeout: 4000 }),
669
- () => page.locator(`label[for="${act.selector.replace('#', '')}"]`).click({ timeout: 4000 }),
670
- () => page.locator(`label:has-text("${labelHint}")`).first().click({ timeout: 4000 }),
671
- () => page.locator(`label:has(${act.selector})`).click({ timeout: 4000 }),
667
+ () => el.click({ force: true, timeout: 2000 }), // force bypasses visibility
668
+ () => el.check({ force: true, timeout: 2000 }),
669
+ () => page.locator(`label[for="${act.selector.replace('#', '')}"]`).click({ timeout: 2000 }),
670
+ () => page.locator(`label:has-text("${labelHint}")`).first().click({ timeout: 2000 }),
671
+ () => page.locator(`label:has(${act.selector})`).click({ timeout: 2000 }),
672
672
  ]) {
673
673
  try {
674
674
  await fn();
@@ -726,7 +726,7 @@ ${domElements}` + (stepAttachment ? `\n\nThe REFERENCE IMAGE (second image) show
726
726
  }
727
727
  /** Try clicking with multiple selector strategies derived from AI suggestion */
728
728
  async function tryAIClick(page, selector) {
729
- const TIMEOUT = 5000;
729
+ const TIMEOUT = 3000;
730
730
  // Build fallback variants: the AI selector + text-based alternatives
731
731
  const textMatch = selector.match(/:has-text\("([^"]+)"\)|:text\("([^"]+)"\)/);
732
732
  const text = textMatch ? (textMatch[1] || textMatch[2]) : null;
@@ -750,7 +750,7 @@ async function tryAIClick(page, selector) {
750
750
  }
751
751
  /** Fill an autocomplete/typeahead input: type value, wait for dropdown, click first matching option */
752
752
  async function tryAutocomplete(page, labelOrSelector, value) {
753
- const TIMEOUT = 4000;
753
+ const TIMEOUT = 2000;
754
754
  const locators = [
755
755
  page.getByLabel(new RegExp(labelOrSelector, 'i')),
756
756
  page.getByPlaceholder(new RegExp(labelOrSelector, 'i')),
@@ -782,7 +782,7 @@ async function tryAutocomplete(page, labelOrSelector, value) {
782
782
  for (const optSel of optionSelectors) {
783
783
  try {
784
784
  const opt = page.locator(optSel).first();
785
- if (await opt.isVisible({ timeout: 800 })) {
785
+ if (await opt.isVisible({ timeout: 500 })) {
786
786
  await opt.click({ timeout: TIMEOUT });
787
787
  console.log(` ✓ Autocomplete: typed "${value}", clicked option via "${optSel}"`);
788
788
  return true;
@@ -946,7 +946,7 @@ async function tryClickScoped(page, nameRe, target, scope) {
946
946
  return false;
947
947
  }
948
948
  async function tryFill(page, label, value) {
949
- const FAST = 1500;
949
+ const FAST = 800;
950
950
  const labelRe = new RegExp(escapeRegex(label), "i");
951
951
  const variants = labelVariants(label);
952
952
  const attrContains = (attr) => variants
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cutleryapp/agent",
3
- "version": "1.0.34",
3
+ "version": "1.0.35",
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": {