Batch CDP calls: single-evaluate debug info, data-claw-idx tagging, field count logging

- getModalDebugInfo: one evaluate() for heading, buttons, errors (was N+2 calls)
- selectOptionFuzzy: batch-read option texts in one evaluate (was N calls)
- Tag elements with data-claw-idx during snapshot, query by attribute in fill()
  (fixes fragile positional index matching for checkboxes/inputs)
- Log field counts per fill step for debugging

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 14:50:47 -08:00
parent a956b98941
commit d0a40e4654
2 changed files with 81 additions and 104 deletions

View File

@@ -78,30 +78,27 @@ async function getModalDebugInfo(page, modalSelector) {
const modal = await page.$(modalSelector);
if (!modal) return { heading: '', buttons: [], errors: [] };
const heading = await modal.$eval(
'h1, h2, h3, [class*="title"], [class*="heading"]',
el => el.textContent?.trim()?.slice(0, 60) || ''
).catch(() => '');
// Single evaluate to extract all debug info at once
return await modal.evaluate((el) => {
const headingEl = el.querySelector('h1, h2, h3, [class*="title"], [class*="heading"]');
const heading = headingEl?.textContent?.trim()?.slice(0, 60) || '';
const buttonEls = await modal.$$('button, [role="button"]');
const buttons = [];
for (const b of buttonEls) {
const info = await b.evaluate(el => ({
text: (el.innerText || el.textContent || '').trim().slice(0, 50),
aria: el.getAttribute('aria-label'),
disabled: el.disabled,
})).catch(() => null);
if (info && (info.text || info.aria)) buttons.push(info);
}
const buttons = [];
for (const b of el.querySelectorAll('button, [role="button"]')) {
const text = (b.innerText || b.textContent || '').trim().slice(0, 50);
const aria = b.getAttribute('aria-label');
const disabled = b.disabled;
if (text || aria) buttons.push({ text, aria, disabled });
}
const errorEls = await modal.$$('[class*="error"], [aria-invalid="true"], .artdeco-inline-feedback--error');
const errors = [];
for (const e of errorEls) {
const text = await e.evaluate(el => el.textContent?.trim()?.slice(0, 60) || '').catch(() => '');
if (text) errors.push(text);
}
const errors = [];
for (const e of el.querySelectorAll('[class*="error"], [aria-invalid="true"], .artdeco-inline-feedback--error')) {
const text = e.textContent?.trim()?.slice(0, 60) || '';
if (text) errors.push(text);
}
return { heading, buttons, errors };
return { heading, buttons, errors };
}).catch(() => ({ heading: '', buttons: [], errors: [] }));
}
/**