From 961f27afb0b4b4978001762a52d80af9c07edc8c Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Wed, 27 May 2026 14:33:21 +0300 Subject: [PATCH] refactor(web-test): deleteTableRow coords + reuse countGridRows (S10) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 19 LOC inline cellCoords + 8 LOC inline row-count в engine/table/grid.mjs deleteTableRow → новый findDeleteRowCoordsScript в dom/grid.mjs + переиспользован существующий countGridRowsScript (dom/grid.mjs:268, добавлен в S5). Engine-сторона deleteTableRow становится чистым оркестратором: resolve grid → get coords → click → Delete → count rows. DOM-extraction iter 2 / S10 из плана. Точечный регресс 05-table зелёный + полный регресс 19/19 зелёный. Co-Authored-By: Claude Opus 4.7 (1M context) --- .claude/skills/web-test/scripts/dom/grid.mjs | 28 +++++++++++++++- .../web-test/scripts/engine/table/grid.mjs | 32 +++---------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/.claude/skills/web-test/scripts/dom/grid.mjs b/.claude/skills/web-test/scripts/dom/grid.mjs index 82c66806..28bc9eec 100644 --- a/.claude/skills/web-test/scripts/dom/grid.mjs +++ b/.claude/skills/web-test/scripts/dom/grid.mjs @@ -1,4 +1,4 @@ -// web-test dom/grid v1.2 — grid resolution + table reading + edit-time helpers +// web-test dom/grid v1.3 — grid resolution + table reading + edit-time helpers // Source: https://github.com/Nikolay-Shirokov/cc-1c-skills /** @@ -261,6 +261,32 @@ function gridResolver(gridSelector) { : `(() => { const grids = [...document.querySelectorAll('.grid')].filter(el => el.offsetWidth > 0); return grids[grids.length - 1]; })()`; } +/** + * Find center coords of a target row for click-select (used by deleteTableRow). + * Picks the second visible gridBox container in the row (skips row-number/checkbox col). + * + * Returns `{ x, y, total } | { error: 'no_grid'|'no_grid_body'|'row_out_of_range'|'no_cell', total? }`. + */ +export function findDeleteRowCoordsScript(gridSelector, row) { + return `(() => { + const grid = ${gridResolver(gridSelector)}; + if (!grid) return { error: 'no_grid' }; + const body = grid.querySelector('.gridBody'); + if (!body) return { error: 'no_grid_body' }; + const rows = [...body.querySelectorAll('.gridLine')]; + if (${row} >= rows.length) return { error: 'row_out_of_range', total: rows.length }; + const line = rows[${row}]; + // Use visible gridBox containers (not gridBoxText) to avoid clicking checkboxes + const boxes = [...line.children].filter(b => b.offsetWidth > 0 && !b.classList.contains('gridBoxComp')); + // Skip first column (row number / checkbox) — pick second visible box + const box = boxes.length > 1 ? boxes[1] : boxes[0]; + if (!box) return { error: 'no_cell' }; + const cell = box.querySelector('.gridBoxText') || box; + const r = cell.getBoundingClientRect(); + return { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2), total: rows.length }; + })()`; +} + /** * Count `.gridLine` rows in the body of the target grid. * Returns the row count, or `0` when grid/body absent. diff --git a/.claude/skills/web-test/scripts/engine/table/grid.mjs b/.claude/skills/web-test/scripts/engine/table/grid.mjs index 55bf457c..70601d5e 100644 --- a/.claude/skills/web-test/scripts/engine/table/grid.mjs +++ b/.claude/skills/web-test/scripts/engine/table/grid.mjs @@ -1,4 +1,4 @@ -// web-test table/grid v1.18 — Form-grid operations: read table rows, fill rows, delete rows. +// web-test table/grid v1.19 — Form-grid operations: read table rows, fill rows, delete rows. // Source: https://github.com/Nikolay-Shirokov/cc-1c-skills // // "Grid" в терминах 1С — таблица на форме (.gridLine/.gridBody/.grid в DOM): @@ -7,6 +7,7 @@ import { page, ensureConnected } from '../core/state.mjs'; import { detectFormScript, readTableScript, resolveGridScript } from '../../dom.mjs'; +import { findDeleteRowCoordsScript, countGridRowsScript } from '../../dom/grid.mjs'; import { dismissPendingErrors } from '../core/errors.mjs'; import { waitForStable } from '../core/wait.mjs'; import { clickElement } from '../core/click.mjs'; @@ -56,25 +57,7 @@ export async function deleteTableRow(row, { tab, table } = {}) { } // 2. Find the target row and click to select it - const cellCoords = 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 { error: 'no_grid' }; - const body = grid.querySelector('.gridBody'); - if (!body) return { error: 'no_grid_body' }; - const rows = [...body.querySelectorAll('.gridLine')]; - if (${row} >= rows.length) return { error: 'row_out_of_range', total: rows.length }; - const line = rows[${row}]; - // Use visible gridBox containers (not gridBoxText) to avoid clicking checkboxes - const boxes = [...line.children].filter(b => b.offsetWidth > 0 && !b.classList.contains('gridBoxComp')); - // Skip first column (row number / checkbox) — pick second visible box - const box = boxes.length > 1 ? boxes[1] : boxes[0]; - if (!box) return { error: 'no_cell' }; - const cell = box.querySelector('.gridBoxText') || box; - const r = cell.getBoundingClientRect(); - return { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2), total: rows.length }; - })()`); + const cellCoords = await page.evaluate(findDeleteRowCoordsScript(gridSelector, row)); if (cellCoords.error) throw new Error(`deleteTableRow: ${cellCoords.error}${cellCoords.total ? ' (total rows: ' + cellCoords.total + ')' : ''}`); @@ -89,14 +72,7 @@ export async function deleteTableRow(row, { tab, table } = {}) { await waitForStable(); // 4. Count rows after deletion - const rowsAfter = 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 0; - const body = grid.querySelector('.gridBody'); - return body ? body.querySelectorAll('.gridLine').length : 0; - })()`); + const rowsAfter = await page.evaluate(countGridRowsScript(gridSelector)); return returnFormState({ deleted: row, rowsBefore, rowsAfter }); }