From 9f5e244f68f1a3c4ea4a74919314d4195162666a Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Mon, 16 Mar 2026 12:59:06 +0300 Subject: [PATCH] fix(web-test): fillTableRow add+checkbox targets correct row via addedRowIdx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tab navigation skips checkbox cells (no INPUT). After Tab fill, unfilled checkbox fields are retried via direct click. Previously the retry hit the wrong row because the selected row shifted after Tab/commit. Now we record row count before "Добавить" click and use that index for the retry, ensuring checkboxes land on the same row as the text fields. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/skills/web-test/scripts/browser.mjs | 48 +++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/.claude/skills/web-test/scripts/browser.mjs b/.claude/skills/web-test/scripts/browser.mjs index f6240b25..2a279df0 100644 --- a/.claude/skills/web-test/scripts/browser.mjs +++ b/.claude/skills/web-test/scripts/browser.mjs @@ -2110,7 +2110,16 @@ export async function fillTableRow(fields, { tab, add, row, table } = {}) { } // 2. Add new row if requested + let addedRowIdx = -1; if (add) { + // Count rows before add — new row will be appended at this index + addedRowIdx = await page.evaluate(`(() => { + const grid = ${gridSelector + ? `document.querySelector(${JSON.stringify(gridSelector)})` + : `(() => { const grids = [...document.querySelectorAll('.grid')].filter(el => el.offsetWidth > 0); return grids[grids.length - 1]; })()`}; + const body = grid?.querySelector('.gridBody'); + return body ? body.querySelectorAll('.gridLine').length : 0; + })()`); await clickElement('Добавить', { table }); // Poll for edit mode (INPUT inside grid) instead of fixed 1000ms wait for (let aw = 0; aw < 6; aw++) { @@ -3036,6 +3045,45 @@ export async function fillTableRow(fields, { tab, add, row, table } = {}) { } const notFilled = [...pending].filter(([_, info]) => !info.filled).map(([key]) => key); + + // Retry unfilled checkbox fields via direct click (Tab skips checkbox cells) + if (notFilled.length > 0) { + const checkboxFields = {}; + for (const key of notFilled) { + const val = String(pending.get(key).value).toLowerCase().trim(); + if (['true', 'false', 'да', 'нет', '1', '0', 'yes', 'no'].includes(val)) { + checkboxFields[key] = pending.get(key).value; + } + } + if (Object.keys(checkboxFields).length > 0) { + // Use row index: addedRowIdx (from add mode) or fallback to selected row + const currentRow = addedRowIdx >= 0 ? addedRowIdx : (row != null ? row : await page.evaluate(`(() => { + 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 -1; + const body = grid.querySelector('.gridBody'); + if (!body) return -1; + const lines = [...body.querySelectorAll('.gridLine')]; + const sel = lines.findIndex(l => l.classList.contains('selected')); + return sel >= 0 ? sel : lines.length - 1; + })()`) + ); + if (currentRow >= 0) { + const more = await fillTableRow(checkboxFields, { row: currentRow, table }); + if (Array.isArray(more)) { + results.push(...more); + } else if (more?.filled) { + results.push(...more.filled); + } + for (const key of Object.keys(checkboxFields)) { + const idx = notFilled.indexOf(key); + if (idx >= 0) notFilled.splice(idx, 1); + } + } + } + } + const formData = await getFormState(); const result = { filled: results }; if (notFilled.length > 0) result.notFilled = notFilled;