feat(web-test): clickElement on tree nodes defaults to select, toggle is explicit

Previously clickElement always toggled expand/collapse on tree nodes.
Now default = select (click text), and { toggle: true } = expand/collapse
(click tree icon). Hint in response guides the model to use toggle when needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-03-14 18:47:52 +03:00
co-authored by Claude Opus 4.6
parent 31792a8a2d
commit 55ab172ba4
+36 -27
View File
@@ -1441,7 +1441,7 @@ export async function fillFields(fields) {
} }
/** Click a button/hyperlink/tab on the current form. Use {dblclick: true} to double-click (open items from lists). */ /** Click a button/hyperlink/tab on the current form. Use {dblclick: true} to double-click (open items from lists). */
export async function clickElement(text, { dblclick, table } = {}) { export async function clickElement(text, { dblclick, table, toggle } = {}) {
ensureConnected(); ensureConnected();
await dismissPendingErrors(); await dismissPendingErrors();
if (highlightMode) try { await highlight(text, { table }); await page.waitForTimeout(500); await unhighlight(); } catch {} if (highlightMode) try { await highlight(text, { table }); await page.waitForTimeout(500); await unhighlight(); } catch {}
@@ -1557,39 +1557,48 @@ export async function clickElement(text, { dblclick, table } = {}) {
return state; return state;
} }
if (target.kind === 'gridTreeNode') { if (target.kind === 'gridTreeNode') {
// Tree node: click the tree expand/collapse icon [tree="true"] for toggle if (toggle) {
const treeIconCoords = await page.evaluate(`(() => { // Toggle: click the tree expand/collapse icon [tree="true"]
const p = ${JSON.stringify(`form${formNum}_`)}; const treeIconCoords = await page.evaluate(`(() => {
const gridSel = ${JSON.stringify(target.gridId ? '#' + target.gridId : null)}; const p = ${JSON.stringify(`form${formNum}_`)};
const grid = gridSel ? document.querySelector(gridSel) : document.querySelector('[id^="' + p + '"].grid'); const gridSel = ${JSON.stringify(target.gridId ? '#' + target.gridId : null)};
const body = grid?.querySelector('.gridBody'); const grid = gridSel ? document.querySelector(gridSel) : document.querySelector('[id^="' + p + '"].grid');
if (!body) return null; const body = grid?.querySelector('.gridBody');
const lines = [...body.querySelectorAll('.gridLine')]; if (!body) return null;
for (const line of lines) { const lines = [...body.querySelectorAll('.gridLine')];
const textBoxes = [...line.querySelectorAll('.gridBoxText')].filter(b => b.offsetWidth > 0); for (const line of lines) {
const text = textBoxes[0]?.innerText?.trim() || ''; const textBoxes = [...line.querySelectorAll('.gridBoxText')].filter(b => b.offsetWidth > 0);
if (text.toLowerCase().replace(/ё/gi, 'е') === ${JSON.stringify(target.name.toLowerCase().replace(/ё/gi, 'е'))}) { const text = textBoxes[0]?.innerText?.trim() || '';
const treeIcon = line.querySelector('.gridBoxImg [tree="true"]'); if (text.toLowerCase().replace(/ё/gi, 'е') === ${JSON.stringify(target.name.toLowerCase().replace(/ё/gi, 'е'))}) {
if (treeIcon) { const treeIcon = line.querySelector('.gridBoxImg [tree="true"]');
const r = treeIcon.getBoundingClientRect(); if (treeIcon) {
return { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2) }; const r = treeIcon.getBoundingClientRect();
return { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2) };
}
} }
} }
return null;
})()`);
if (treeIconCoords) {
await page.mouse.click(treeIconCoords.x, treeIconCoords.y);
} else {
// Fallback: select row and use +/- keys
await page.mouse.click(target.x, target.y);
await page.waitForTimeout(300);
await page.keyboard.press('NumpadAdd');
} }
return null; await waitForStable(formNum);
})()`); const state = await getFormState();
if (treeIconCoords) { state.clicked = { kind: 'gridTreeNode', name: target.name, toggled: true };
await page.mouse.click(treeIconCoords.x, treeIconCoords.y); state.hint = 'Tree node toggled. Use readTable to see updated tree.';
} else { return state;
// Fallback: select row and use +/- keys
await page.mouse.click(target.x, target.y);
await page.waitForTimeout(300);
await page.keyboard.press('NumpadAdd');
} }
// Default: select row (click text, no expand/collapse)
await page.mouse.click(target.x, target.y);
await waitForStable(formNum); await waitForStable(formNum);
const state = await getFormState(); const state = await getFormState();
state.clicked = { kind: 'gridTreeNode', name: target.name }; state.clicked = { kind: 'gridTreeNode', name: target.name };
state.hint = 'Tree node toggled. Use web_table to see updated tree.'; state.hint = 'Row selected. Use { toggle: true } to expand/collapse.';
return state; return state;
} }
if (target.kind === 'gridRow') { if (target.kind === 'gridRow') {