fix(web-test): состояние группы по контролу сворачивания, а не по вёрстке содержимого

На боевой форме вскрылись случаи, которые прежнее правило не покрывало. Замеры показали,
что любая эвристика «по первому сиблингу за заголовком» нежизнеспособна:

- служебная обёртка .logicGroupContainer пишется двумя способами (у таблицы
  <дочерний>#group_div, у вложенной группы <дочерний>_div) — знали только первый;
- display самой обёртки плавает: block до первого тогла, none после;
- первые узлы группы могут быть скрыты своей логикой, а видимое содержимое идёт дальше
  по цепочке — раскрытая группа читалась как свёрнутая, и постусловие роняло успешный клик.

Теперь состояние берётся из контрола сворачивания: у варианта «картинка» — кадр gx спрайта
hideshow у каретки (полярность обратна дереву в dom/grid.mjs), у варианта «гиперссылка»
каретки нет, там принадлежность по отступу — дети группы смещены глубже её заголовка,
свободный сосед стоит на уровне заголовка. База отсчёта — левый край блока заголовка
(каретка сдвигает текст вправо), обход ограничен: у последней свёрнутой группы границы за
ней нет, и первый видимый узел нашёлся через 107 сиблингов в чужой ветке формы.

Клик по заголовку группы теперь сперва скроллит цель в вид: цель кликается по координатам,
и ниже вьюпорта клик молча не доходил.

Ответ на клик отдаёт clicked.group (техническое имя) и clicked.title (текущий заголовок):
заголовок ключом быть не может — он повторяется между блоками формы и меняется при
раскрытии (CollapsedRepresentationTitle), после чего клик по прежнему тексту не находит
элемент. При смене заголовка hint говорит, чем кликать дальше.

Фикстура: вложенная группа первым ребёнком, «скрыт первый узел» в двух вариантах контрола,
группа с меняющимся заголовком в конце формы (уезжает за вьюпорт). Каждый кейс проверен на
красноту без своей правки.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-07-28 16:12:07 +03:00
co-authored by Claude Opus 5
parent 006e64405c
commit d0e81a1715
7 changed files with 257 additions and 45 deletions
@@ -1372,6 +1372,47 @@ export const steps = [
]},
],
},
// ВЛОЖЕННАЯ ГРУППА ПЕРВЫМ РЕБЁНКОМ. Служебную обёртку .logicGroupContainer платформа
// пишет двумя способами: у таблицы — <дочерний>#group_div (группа выше), у вложенной
// группы — <дочерний>_div. Правило, узнающее только первую форму, на этой группе
// читает display самой обёртки (block) и рапортует «раскрыта» у свёрнутой.
{ group: 'collapsible', name: 'ГруппаСВложенной', title: 'Свёрнутая с вложенной группой',
collapsed: true, showTitle: true, children: [
{ group: 'vertical', name: 'ВложеннаяОбычная', title: 'Вложенная группа', showTitle: true,
children: [
{ label: 'ВнутриВложенной', title: 'Содержимое вложенной группы' },
],
},
],
},
// ПЕРВЫЙ УЗЕЛ СКРЫТ СВОЕЙ ЛОГИКОЙ, видимое содержимое идёт дальше по цепочке сиблингов
// (на боевой форме так ведёт себя таблица со скрытой командной панелью). Правило
// «display первого контент-узла» здесь врёт в обе стороны: у раскрытой группы читает
// «свёрнута», из-за чего clickElement({expand}) считает клик несработавшим.
// Два варианта контрола: заголовок-гиперссылка и картинка-каретка.
{ group: 'collapsible', name: 'ГруппаСкрытыйПервый', title: 'Скрыт первый узел',
collapsed: true, showTitle: true, children: [
{ label: 'СкрытыйПервыйУзел', title: 'Эта декорация скрыта', visible: false },
{ label: 'ВидимыйВторойУзел', title: 'Видно только эту декорацию' },
],
},
{ group: 'collapsible', name: 'ГруппаСкрытыйПервыйКартинка', title: 'Скрыт первый узел (картинка)',
controlRepresentation: 'Picture', collapsed: true, showTitle: true, children: [
{ label: 'СкрытыйПервыйУзелК', title: 'Эта декорация скрыта (картинка)', visible: false },
{ label: 'ВидимыйВторойУзелК', title: 'Видно только эту декорацию (картинка)' },
],
},
// МЕНЯЮЩИЙСЯ ЗАГОЛОВОК (CollapsedRepresentationTitle): свёрнута — «Показать подробности»,
// раскрыта — «Скрыть подробности». Повторный клик по прежнему тексту уже не найдёт
// элемент, поэтому ответ на клик отдаёт техническое имя группы и её текущий заголовок.
// Стоит ПОСЛЕДНЕЙ на форме: с раскрытой группой-с-таблицей уезжает ниже вьюпорта, так что
// заодно покрывает клик по цели за пределами видимой области (координатный клик туда
// не доходил — молчаливый no-op).
{ group: 'collapsible', name: 'ГруппаМеняющийсяЗаголовок', title: 'Скрыть подробности',
collapsedTitle: 'Показать подробности', collapsed: true, showTitle: true, children: [
{ label: 'ВнутриПодробностей', title: 'Содержимое подробностей' },
],
},
],
},
args: { '-JsonPath': '{inputFile}', '-OutputPath': '{workDir}/DataProcessors/СтраницаНастроек/Forms/ФормаОбработки/Ext/Form.xml' },