From 09bc0d00b8b8f89b0ee40a92adf083f65571072b Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Wed, 1 Apr 2026 14:17:40 +0300 Subject: [PATCH] fix(web-test): use target.y coordinates to find expand icon row MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The expand/collapse code re-searched for the target row by first-cell text, which was ambiguous when parent and child rows share the same prefix (e.g. "БУ"). This caused expand to hit the wrong (already- expanded) row and skip. Use target.y from the initial findClickTarget instead — matches the exact row. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/skills/web-test/scripts/browser.mjs | 36 ++++++++++----------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/.claude/skills/web-test/scripts/browser.mjs b/.claude/skills/web-test/scripts/browser.mjs index 3b274de9..f2b340eb 100644 --- a/.claude/skills/web-test/scripts/browser.mjs +++ b/.claude/skills/web-test/scripts/browser.mjs @@ -2063,17 +2063,16 @@ export async function clickElement(text, { dblclick, table, toggle, expand, modi const grid = gridSel ? document.querySelector(gridSel) : document.querySelector('[id^="' + p + '"].grid'); const body = grid?.querySelector('.gridBody'); if (!body) return null; + const targetY = ${target.y}; const lines = [...body.querySelectorAll('.gridLine')]; for (const line of lines) { - const textBoxes = [...line.querySelectorAll('.gridBoxText')].filter(b => b.offsetWidth > 0); - const text = textBoxes[0]?.innerText?.trim() || ''; - if (text.toLowerCase().replace(/ё/gi, 'е') === ${JSON.stringify(target.name.toLowerCase().replace(/ё/gi, 'е'))}) { - const icon = line.querySelector('.gridListH, .gridListV'); - if (icon) { - const r = icon.getBoundingClientRect(); - const isExpanded = !!icon.classList.contains('gridListV'); - return { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2), isExpanded }; - } + const lr = line.getBoundingClientRect(); + if (targetY < lr.top || targetY > lr.bottom) continue; + const icon = line.querySelector('.gridListH, .gridListV'); + if (icon) { + const r = icon.getBoundingClientRect(); + const isExpanded = !!icon.classList.contains('gridListV'); + return { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2), isExpanded }; } } return null; @@ -2112,18 +2111,17 @@ export async function clickElement(text, { dblclick, table, toggle, expand, modi const grid = gridSel ? document.querySelector(gridSel) : document.querySelector('[id^="' + p + '"].grid'); const body = grid?.querySelector('.gridBody'); if (!body) return null; + const targetY = ${target.y}; const lines = [...body.querySelectorAll('.gridLine')]; for (const line of lines) { - const textBoxes = [...line.querySelectorAll('.gridBoxText')].filter(b => b.offsetWidth > 0); - const text = textBoxes[0]?.innerText?.trim() || ''; - if (text.toLowerCase().replace(/ё/gi, 'е') === ${JSON.stringify(target.name.toLowerCase().replace(/ё/gi, 'е'))}) { - const treeIcon = line.querySelector('.gridBoxImg [tree="true"]'); - if (treeIcon) { - const r = treeIcon.getBoundingClientRect(); - const bg = treeIcon.style.backgroundImage || ''; - const isExpanded = bg.includes('gx=0'); - return { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2), isExpanded }; - } + const lr = line.getBoundingClientRect(); + if (targetY < lr.top || targetY > lr.bottom) continue; + const treeIcon = line.querySelector('.gridBoxImg [tree="true"]'); + if (treeIcon) { + const r = treeIcon.getBoundingClientRect(); + const bg = treeIcon.style.backgroundImage || ''; + const isExpanded = bg.includes('gx=0'); + return { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2), isExpanded }; } } return null;