From 4507d9b59c8383e40fc5f58af5e7e51f8f3da6ed Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Thu, 12 Mar 2026 15:00:15 +0300 Subject: [PATCH] feat(web-test): highlight() now finds form groups and panels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added group/panel search step to highlight() — matches by visible title or internal name (e.g. highlight('Оргструктура') finds the group container). Search priority: popups → commands → form elements → groups → sections. Co-Authored-By: Claude Opus 4.6 --- .claude/skills/web-test/recording.md | 5 ++-- .claude/skills/web-test/scripts/browser.mjs | 32 ++++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/.claude/skills/web-test/recording.md b/.claude/skills/web-test/recording.md index ce1d0d2f..8cd933de 100644 --- a/.claude/skills/web-test/recording.md +++ b/.claude/skills/web-test/recording.md @@ -137,10 +137,11 @@ Manually highlight a UI element by name (fuzzy match). Places a semi-transparent | Parameter | Type | Description | |-----------|------|-------------| -| `text` | string | Element name — button, link, field, section, or command | +| `text` | string | Element name — button, link, field, group/panel, section, or command | - Fuzzy match order: exact → startsWith → includes -- Searches form elements first, then sections/commands +- Search priority: popup items → commands → form elements (buttons, fields) → **form groups/panels** → sections +- Groups are matched by visible title or internal name (e.g., `highlight('Оргструктура')` finds the group panel) - `pointer-events: none` — does not block clicks ### `unhighlight()` diff --git a/.claude/skills/web-test/scripts/browser.mjs b/.claude/skills/web-test/scripts/browser.mjs index 403f3309..fa4011d1 100644 --- a/.claude/skills/web-test/scripts/browser.mjs +++ b/.claude/skills/web-test/scripts/browser.mjs @@ -3579,7 +3579,37 @@ export async function highlight(text, opts = {}) { } } - // 3. Fallback: sections (sidebar navigation) + // 3. Form groups/panels (containers with title text or matching ID name) + if (!elId) { + const formNum = elId === null ? await page.evaluate(detectFormScript()) : null; + if (formNum !== null) { + elId = await page.evaluate(`(() => { + const norm = s => (s?.trim().replace(/\\u00a0/g, ' ') || '').replace(/ё/gi, 'е'); + const target = ${JSON.stringify(normYo(text.toLowerCase()))}; + const p = 'form' + ${formNum} + '_'; + // Collect visible group containers — _container or _div elements + const groups = [...document.querySelectorAll('[id^="' + p + '"][id$="_container"], [id^="' + p + '"][id$="_div"]')] + .filter(el => el.offsetWidth > 0 && el.offsetHeight > 0); + const items = groups.map(el => { + const idName = el.id.replace(p, '').replace(/_(container|div)$/, ''); + // Try to find a visible title/label for this group + const titleEl = document.getElementById(p + idName + '#title_text') + || document.getElementById(p + idName + '_title_text'); + const label = norm(titleEl?.innerText || '').toLowerCase(); + const name = norm(idName).toLowerCase(); + return { id: el.id, name, label }; + }); + // Fuzzy match: exact label → exact name → startsWith → includes + let found = items.find(i => i.label === target); + if (!found) found = items.find(i => i.name === target); + if (!found) found = items.find(i => i.label.startsWith(target) || i.name.startsWith(target)); + if (!found) found = items.find(i => i.label.includes(target) || i.name.includes(target)); + return found ? found.id : null; + })()`); + } + } + + // 4. Fallback: sections (sidebar navigation) if (!elId) { elId = await page.evaluate(`(() => { const norm = s => (s?.trim().replace(/\\u00a0/g, ' ') || '').replace(/ё/gi, 'е');