mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-18 16:49:41 +03:00
refactor(web-test): этап D.12 — fillTableRow → row-fill.mjs, deleteTableRow → grid.mjs
table/row-fill.mjs (~1230 LOC): fillTableRow целиком, как entry-point. table/grid.mjs: добавлен deleteTableRow + расширены импорты (clickElement, dismissPendingErrors, waitForStable, getFormState). Дальнейший распил fillTableRow на под-хелперы (trySelect/readVisibleRows/ pickValueWithOptionalType/enterEditMode/fillCellSequentially per плана §12.1-12.3) отложен — при необходимости создаём table/row-fill/*.mjs subfolder. browser.mjs: 1532 → 249 LOC (-84% от baseline 6293). 05-table регресс зелёный. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,11 @@
|
|||||||
|
|
||||||
import { page, ensureConnected } from '../core/state.mjs';
|
import { page, ensureConnected } from '../core/state.mjs';
|
||||||
import { detectFormScript, readTableScript, resolveGridScript } from '../dom.mjs';
|
import { detectFormScript, readTableScript, resolveGridScript } from '../dom.mjs';
|
||||||
|
import { dismissPendingErrors } from '../core/errors.mjs';
|
||||||
|
import { waitForStable } from '../core/wait.mjs';
|
||||||
|
import { clickElement } from '../core/click.mjs';
|
||||||
|
// getFormState lives in browser.mjs.
|
||||||
|
import { getFormState } from '../browser.mjs';
|
||||||
|
|
||||||
/** Read structured table data with pagination. Returns columns, rows, total count. */
|
/** Read structured table data with pagination. Returns columns, rows, total count. */
|
||||||
export async function readTable({ maxRows = 20, offset = 0, table } = {}) {
|
export async function readTable({ maxRows = 20, offset = 0, table } = {}) {
|
||||||
@@ -21,3 +26,79 @@ export async function readTable({ maxRows = 20, offset = 0, table } = {}) {
|
|||||||
}
|
}
|
||||||
return await page.evaluate(readTableScript(formNum, { maxRows, offset, gridSelector }));
|
return await page.evaluate(readTableScript(formNum, { maxRows, offset, gridSelector }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a row from the current table part.
|
||||||
|
* Single click to select the row, then Delete key to remove it.
|
||||||
|
*
|
||||||
|
* @param {number} row - 0-based row index to delete
|
||||||
|
* @param {Object} [options]
|
||||||
|
* @param {string} [options.tab] - Switch to this form tab before operating
|
||||||
|
* @returns {{ deleted, rowsBefore, rowsAfter, form }}
|
||||||
|
*/
|
||||||
|
export async function deleteTableRow(row, { tab, table } = {}) {
|
||||||
|
ensureConnected();
|
||||||
|
await dismissPendingErrors();
|
||||||
|
const formNum = await page.evaluate(detectFormScript());
|
||||||
|
if (formNum === null) throw new Error('deleteTableRow: no form found');
|
||||||
|
|
||||||
|
// Pre-resolve grid when table is specified
|
||||||
|
let gridSelector;
|
||||||
|
if (table) {
|
||||||
|
const resolved = await page.evaluate(resolveGridScript(formNum, table));
|
||||||
|
if (resolved.error) throw new Error(`deleteTableRow: table "${table}" not found. Available: ${resolved.available?.map(a => a.name).join(', ') || 'none'}`);
|
||||||
|
gridSelector = resolved.gridSelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Switch tab if requested
|
||||||
|
if (tab) {
|
||||||
|
await clickElement(tab);
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 };
|
||||||
|
})()`);
|
||||||
|
|
||||||
|
if (cellCoords.error) throw new Error(`deleteTableRow: ${cellCoords.error}${cellCoords.total ? ' (total rows: ' + cellCoords.total + ')' : ''}`);
|
||||||
|
|
||||||
|
const rowsBefore = cellCoords.total;
|
||||||
|
|
||||||
|
// Single click to select the row
|
||||||
|
await page.mouse.click(cellCoords.x, cellCoords.y);
|
||||||
|
await page.waitForTimeout(300);
|
||||||
|
|
||||||
|
// 3. Press Delete to remove the row
|
||||||
|
await page.keyboard.press('Delete');
|
||||||
|
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 formData = await getFormState();
|
||||||
|
return { deleted: row, rowsBefore, rowsAfter, form: formData };
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user