feat(web-test): фокус на поле ввода через clickElement (fallback)

clickElement как последний fallback (без table) фокусирует одноимённое
поле ввода, не меняя значение — возвращает focused:{field,id,ok}.
Закрывает пробел: клавиши F4/Shift+F4 требовали сфокусированного поля,
но штатного примитива фокуса не было.

- dom/forms.mjs: резолв input.editInput/textarea по имени/заголовку
  последним шагом findClickTargetScript; имена полей в available
- click-form.mjs: focusFormField (клик по инпуту + isInputFocused → ok)
- click.mjs: ветка диспетчера kind === field
- SKILL.md + docs/web-test-guide.md: focused в extras, пример focus→F4
- tests: 19-focus-field.test.mjs (focus/F4/регресс/негатив)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-05-29 22:01:45 +03:00
parent 3a89aa21e6
commit f424d2ac70
7 changed files with 136 additions and 12 deletions
@@ -1,4 +1,4 @@
// web-test core/click v1.21 — clickElement dispatcher: routes to spreadsheet / popup / grid-row / form-element handlers by target kind.
// web-test core/click v1.22 — clickElement dispatcher: routes to spreadsheet / popup / grid-row / form-element / field-focus handlers by target kind.
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import { page, ensureConnected, highlightMode } from './state.mjs';
@@ -17,7 +17,7 @@ import { clickGridCell } from '../table/click-cell.mjs';
import {
clickConfirmationButton, tryClickPopupItem,
} from '../forms/click-popup.mjs';
import { clickFormTarget } from '../forms/click-form.mjs';
import { clickFormTarget, focusFormField } from '../forms/click-form.mjs';
import {
clickSpreadsheetCell, findSpreadsheetCellByText,
} from '../spreadsheet/spreadsheet.mjs';
@@ -121,6 +121,7 @@ export async function clickElement(text, { dblclick, table, toggle, expand, modi
if (target.kind === 'gridGroup' || target.kind === 'gridParent') return await clickGridGroupTarget(target, ctx);
if (target.kind === 'gridTreeNode') return await clickGridTreeNodeTarget(target, ctx);
if (target.kind === 'gridRow') return await clickGridRowTarget(target, ctx);
if (target.kind === 'field') return await focusFormField(target, ctx);
return await clickFormTarget(target, ctx);
} finally {
if (highlightMode) try { await unhighlight(); } catch {}
@@ -1,4 +1,4 @@
// web-test forms/click-form v1.0 — click handler for form-element targets: button, tab, submenu, link.
// web-test forms/click-form v1.1 — click handler for form-element targets: button, tab, submenu, link, field-focus.
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
//
// Called by core/click.mjs dispatcher after target is found.
@@ -12,7 +12,7 @@ import {
} from '../../dom.mjs';
import { checkForErrors } from '../core/errors.mjs';
import { waitForStable, startNetworkMonitor } from '../core/wait.mjs';
import { safeClick, returnFormState } from '../core/helpers.mjs';
import { safeClick, returnFormState, isInputFocused } from '../core/helpers.mjs';
/**
* Click a form target (button, tab, submenu, link) using its resolved {kind, id, x, y, name}.
@@ -105,3 +105,18 @@ export async function clickFormTarget(target, ctx) {
if (netMonitor) try { await netMonitor.cleanup(); } catch {}
}
}
/**
* Focus a form input field (last-resort target kind: 'field') by clicking the input itself —
* does NOT change its value. Lets the caller then drive focus-dependent shortcuts
* (F4 selection form, Shift+F4 clear, etc.) via getPage().keyboard.
* Returns flat form state with `focused: { field, id, ok }`; `ok` reflects whether the
* input actually received focus (false for disabled/readonly fields). Never throws on ok=false.
*/
export async function focusFormField(target, ctx) {
const selector = `[id="${target.id}"]`;
await safeClick(selector, { timeout: 5000 });
await waitForStable(ctx.formNum);
const ok = await isInputFocused({ allowTextarea: true });
return returnFormState({ focused: { field: target.name, id: target.id, ok } });
}