refactor(web-test): returnFormState idem дедуп (Phase 2, 5 сайтов)

Дедуп 5 идемпотентных хвостов action-функций — паттерн
getFormState + state.X = ... + checkForErrors + if(err) state.errors = err + return
сводится к одному returnFormState(extras). Поведение identical.

- core/click.mjs: ветка popupItem (1 сайт)
- forms/select-value.mjs: openFormAndPick helper, DLB dropdown match,
  DLB dropdown no-search-first, selection-form direct 3B (4 сайта)

Аудит upload/returnFormState-audit.md обещал 13 idem, но при разборе:
- click.mjs:final (custom confirmation/hint), close.mjs save=undefined (R3 предупреждение),
  6 сайтов fillReferenceField (приватный shape {field, ok, method, value}, не form-state)
— осознанно НЕ конвертированы. Реальный Phase 2 — 5 сайтов.

Полный регресс 19/19 зелёный (после rebuild стенда — старый стенд накопил
22 Контрагента вместо 4 за прошлые прогоны, не связано с Phase 2).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-05-27 15:09:24 +03:00
parent 961f27afb0
commit 6e09351730
2 changed files with 13 additions and 31 deletions
@@ -1,4 +1,4 @@
// web-test core/click v1.18 — clickElement dispatcher: spreadsheet cells, submenus, grid groups/trees, buttons/links, tabs.
// web-test core/click v1.19 — clickElement dispatcher: spreadsheet cells, submenus, grid groups/trees, buttons/links, tabs.
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import {
@@ -90,11 +90,7 @@ export async function clickElement(text, { dblclick, table, toggle, expand, modi
await page.mouse.click(found.x, found.y);
}
await waitForStable();
const state = await getFormState();
state.clicked = { kind: 'popupItem', name: found.name };
const err = await checkForErrors();
if (err) state.errors = err;
return state;
return returnFormState({ clicked: { kind: 'popupItem', name: found.name } });
}
// No match in popup — fall through to form elements
}
@@ -1,4 +1,4 @@
// web-test forms/select-value v1.19 — Reference & composite-type value selection: selectValue, fillReferenceField, selection/type-dialog pickers.
// web-test forms/select-value v1.20 — Reference & composite-type value selection: selectValue, fillReferenceField, selection/type-dialog pickers.
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import {
@@ -677,13 +677,10 @@ export async function selectValue(fieldName, searchText, { type } = {}) {
const selFormNum = await detectSelectionForm();
if (selFormNum !== null) {
const pickResult = await pickFromSelectionForm(selFormNum, btn.fieldName, searchText || '', formNum);
const state = await getFormState();
state.selected = { field: btn.fieldName, search: searchText || null, method: 'form' };
if (pickResult.error) state.selected.error = pickResult.error;
if (pickResult.message) state.selected.message = pickResult.message;
const err = await checkForErrors();
if (err) state.errors = err;
return state;
const selected = { field: btn.fieldName, search: searchText || null, method: 'form' };
if (pickResult.error) selected.error = pickResult.error;
if (pickResult.message) selected.message = pickResult.message;
return returnFormState({ selected });
}
return null;
}
@@ -717,11 +714,7 @@ export async function selectValue(fieldName, searchText, { type } = {}) {
// Click via evaluate to bypass div.surface overlay
await clickEddItem(match.name);
await waitForStable();
const state = await getFormState();
state.selected = { field: btn.fieldName, search: searchText, method: 'dropdown' };
const err = await checkForErrors();
if (err) state.errors = err;
return state;
return returnFormState({ selected: { field: btn.fieldName, search: searchText, method: 'dropdown' } });
}
// No match in dropdown — try "Показать все" to open selection form
@@ -755,11 +748,7 @@ export async function selectValue(fieldName, searchText, { type } = {}) {
if (regularItems.length > 0) {
await clickEddItem(regularItems[0].name);
await waitForStable();
const state = await getFormState();
state.selected = { field: btn.fieldName, search: null, picked: regularItems[0].name, method: 'dropdown' };
const err = await checkForErrors();
if (err) state.errors = err;
return state;
return returnFormState({ selected: { field: btn.fieldName, search: null, picked: regularItems[0].name, method: 'dropdown' } });
}
}
@@ -773,13 +762,10 @@ export async function selectValue(fieldName, searchText, { type } = {}) {
throw new Error(`selectValue: field "${btn.fieldName}" opened a type selection dialog — this is a composite-type field. Specify the type: selectValue('${btn.fieldName}', '${searchText || ''}', { type: 'ИмяТипа' })`);
}
const pickResult = await pickFromSelectionForm(selFormNum, btn.fieldName, searchText || '', formNum);
const state = await getFormState();
state.selected = { field: btn.fieldName, search: searchText || null, method: 'form' };
if (pickResult.error) state.selected.error = pickResult.error;
if (pickResult.message) state.selected.message = pickResult.message;
const err = await checkForErrors();
if (err) state.errors = err;
return state;
const selected = { field: btn.fieldName, search: searchText || null, method: 'form' };
if (pickResult.error) selected.error = pickResult.error;
if (pickResult.message) selected.message = pickResult.message;
return returnFormState({ selected });
}
// 3C. Neither popup nor form — try F4 as last resort