From 55b0ffa4fd2f8cfe275a9699bc632be91f7ae4f8 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sat, 14 Mar 2026 14:20:12 +0300 Subject: [PATCH 1/2] fix(web-test): pass table scope to highlight in clickElement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit highlight() was ignoring the table parameter, always highlighting the first matching button (e.g. "Добавить" for Входящие instead of Исходящие). Now clickElement passes { table } to highlight, and highlight pre-resolves the grid via resolveGridScript to pass gridSelector to findClickTargetScript — same pattern as clickElement itself. Co-Authored-By: Claude Opus 4.6 --- .claude/skills/web-test/scripts/browser.mjs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.claude/skills/web-test/scripts/browser.mjs b/.claude/skills/web-test/scripts/browser.mjs index af6a6544..6e47dae5 100644 --- a/.claude/skills/web-test/scripts/browser.mjs +++ b/.claude/skills/web-test/scripts/browser.mjs @@ -1444,7 +1444,7 @@ export async function fillFields(fields) { export async function clickElement(text, { dblclick, table } = {}) { ensureConnected(); await dismissPendingErrors(); - if (highlightMode) try { await highlight(text); await page.waitForTimeout(500); await unhighlight(); } catch {} + if (highlightMode) try { await highlight(text, { table }); await page.waitForTimeout(500); await unhighlight(); } catch {} try { // First check if there's a confirmation dialog — click matching button @@ -4012,7 +4012,7 @@ export async function hideTitleSlide() { */ export async function highlight(text, opts = {}) { ensureConnected(); - const { color = '#e74c3c', padding = 4 } = opts; + const { color = '#e74c3c', padding = 4, table } = opts; // Remove previous highlight first await unhighlight(); @@ -4108,7 +4108,12 @@ export async function highlight(text, opts = {}) { const formNum = await page.evaluate(detectFormScript()); if (formNum !== null) { // 3a. Try button/link/tab/gridRow via findClickTargetScript - const target = await page.evaluate(findClickTargetScript(formNum, text)); + let gridSelector; + if (table) { + const resolved = await page.evaluate(resolveGridScript(formNum, table)); + if (!resolved.error) gridSelector = resolved.gridSelector; + } + const target = await page.evaluate(findClickTargetScript(formNum, text, table ? { tableName: table, gridSelector } : undefined)); if (target && !target.error) { if (target.id) { elId = target.id; From 7a6e63078df63f33dd94492b09bc1eebca10ccef Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sat, 14 Mar 2026 14:24:27 +0300 Subject: [PATCH 2/2] fix(web-test): commit fillTableRow by clicking grid header instead of data row MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clicking a different data row to exit edit mode re-entered edit on that row, blocking subsequent button clicks like "Записать". Now the add-path commit clicks the grid header which cleanly exits edit mode without re-entering it. Co-Authored-By: Claude Opus 4.6 --- .claude/skills/web-test/scripts/browser.mjs | 35 +++++---------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/.claude/skills/web-test/scripts/browser.mjs b/.claude/skills/web-test/scripts/browser.mjs index 6e47dae5..c21a4a1d 100644 --- a/.claude/skills/web-test/scripts/browser.mjs +++ b/.claude/skills/web-test/scripts/browser.mjs @@ -2958,38 +2958,15 @@ export async function fillTableRow(fields, { tab, add, row, table } = {}) { // Tab already pressed — we're on next cell } - // Commit the new row: click on a different row or outside the grid. - // Without this, the row stays in "uncommitted add" state and a subsequent - // Escape (e.g. from closeForm) would cancel the entire row. + // Commit the new row: click on the grid header to exit edit mode. + // Clicking a different data row would re-enter edit mode on that row. + // Without this commit click, the row stays in "uncommitted add" state + // and a subsequent Escape (e.g. from closeForm) would cancel the entire row. const commitTarget = await page.evaluate(`(() => { - // Find the active grid const grid = ${gridSelector ? `document.querySelector(${JSON.stringify(gridSelector)})` : `(() => { const grids = [...document.querySelectorAll('.grid')].filter(el => el.offsetWidth > 0); return grids[grids.length - 1]; })()`}; if (!grid) return null; - const body = grid.querySelector('.gridBody'); - if (!body) return null; - const rows = [...body.querySelectorAll('.gridLine')]; - // Find the currently active row (contains the focused input) - const activeInput = document.activeElement; - let activeRowIdx = -1; - if (activeInput) { - for (let i = 0; i < rows.length; i++) { - if (rows[i].contains(activeInput)) { activeRowIdx = i; break; } - } - } - // Click a DIFFERENT row to commit - const targetIdx = activeRowIdx === 0 ? 1 : 0; - const target = rows[targetIdx]; - if (target) { - const visBoxes = [...target.children].filter(b => b.offsetWidth > 0 && !b.classList.contains('gridBoxComp')); - const box = visBoxes.length > 1 ? visBoxes[1] : visBoxes[0]; - if (box) { - const r = box.getBoundingClientRect(); - return { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2) }; - } - } - // Fallback: click the grid header const head = grid.querySelector('.gridHead'); if (head) { const r = head.getBoundingClientRect(); @@ -3000,6 +2977,10 @@ export async function fillTableRow(fields, { tab, add, row, table } = {}) { if (commitTarget) { await page.mouse.click(commitTarget.x, commitTarget.y); await page.waitForTimeout(500); + } else { + // Fallback: Tab out of the last cell to commit the row + await page.keyboard.press('Tab'); + await page.waitForTimeout(500); } // Dismiss any leftover error modals