From 8b5fed98e04c5fc67fb73d65376227afa00db6e8 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Mon, 11 May 2026 17:43:31 +0300 Subject: [PATCH] =?UTF-8?q?test(web-test):=20M4.E=20=E2=80=94=20hierarchy?= =?UTF-8?q?=20+=20tree-grid=20(=D0=9D=D0=BE=D0=BC=D0=B5=D0=BD=D0=BA=D0=BB?= =?UTF-8?q?=D0=B0=D1=82=D1=83=D1=80=D0=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Новый 08-hierarchy.test.mjs (7 шагов, 24s) — покрывает группы и tree-grid режима «Дерево» на форме списка Номенклатуры через UI переключение viewMode. Без расширения синтетики. - setup: явное переключение в «Иерархический список» через Ещё → Режим просмотра (viewMode сохраняется между сессиями и НЕ сбрасывается «Установить стандартные настройки»). - read-groups (P1): readTable возвращает 2 группы (_kind=group). - group-expand (P1): clickElement({expand:true}) развёртывает группу, внутри 15 элементов. - switch-tree: «Ещё → Режим просмотра → Дерево» → viewMode='tree'. - read-tree (P2): readTable.rows[]._tree (collapsed|expanded) — проверка только наличия поля (состояние сохраняется между сессиями). - tree-expand (P1): defensive свёртка через {expand:false} если узел expanded, затем {expand:true} → kind='gridTreeNode' toggled=true, видны 15 элементов под Товарами. - cleanup: восстановить иерархический список. Замечание: clickElement({expand:true}) — только развернуть (no-op для expanded), {expand:false} — только свернуть, {toggle:true} — безусловно переключить. 05-table/direct-edit-form, edit-dblclick остаются deferred — нужен документ с иерархической ТЧ. Полный регресс 16/16 зелёный (7m 53s). Co-Authored-By: Claude Opus 4.7 (1M context) --- tests/web-test/08-hierarchy.test.mjs | 91 ++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 tests/web-test/08-hierarchy.test.mjs diff --git a/tests/web-test/08-hierarchy.test.mjs b/tests/web-test/08-hierarchy.test.mjs new file mode 100644 index 00000000..6b3171c8 --- /dev/null +++ b/tests/web-test/08-hierarchy.test.mjs @@ -0,0 +1,91 @@ +export const name = 'hierarchy: groups + tree-grid (Номенклатура)'; +export const tags = ['hierarchy']; +export const timeout = 90000; + +export default async function({ navigateSection, openCommand, clickElement, closeForm, readTable, assert, step, log }) { + + await step('setup: открыть Номенклатуру и явно переключиться в иерархический список', async () => { + await navigateSection('Склад'); + await openCommand('Номенклатура'); + // viewMode сохраняется между сессиями в пользовательских настройках формы + // и НЕ сбрасывается «Установить стандартные настройки». Переключаем явно. + await clickElement('Ещё'); + await clickElement('Режим просмотра'); + await clickElement('Иерархический список'); + // Сброс остальных настроек (раскрытие групп, фильтры и т.п.) + await clickElement('Ещё'); + await clickElement('Установить стандартные настройки'); + }); + + await step('read-groups: иерархический список возвращает группы верхнего уровня', async () => { + const t = await readTable(); + log(`total=${t.total} rows=${t.rows?.length} viewMode=${t.viewMode}`); + assert.equal(t.total, 2, 'видны только две группы верхнего уровня'); + assert.ok(t.rows.every(r => r._kind === 'group'), 'все строки — группы (_kind=group)'); + const names = t.rows.map(r => r['Наименование']); + assert.includes(names, 'Товары', 'есть группа Товары'); + assert.includes(names, 'Услуги', 'есть группа Услуги'); + }); + + await step('group-expand: clickElement({expand}) раскрывает группу и показывает элементы', async () => { + const r = await clickElement('Товары', { expand: true }); + log(`clicked: ${JSON.stringify(r.clicked)}`); + assert.equal(r.clicked?.kind, 'gridGroup', 'kind=gridGroup'); + assert.equal(r.clicked?.toggled, true, 'toggled=true'); + const t = await readTable({ maxRows: 30 }); + log(`after expand: total=${t.total}`); + assert.ok(t.total >= 16, `Товары + 15 элементов >= 16 строк (got ${t.total})`); + const parent = t.rows.find(row => row['Наименование'] === 'Товары'); + assert.ok(parent, 'строка-родитель Товары присутствует'); + const items = t.rows.filter(row => /^Товар \d+/.test(row['Наименование'] || '')); + assert.ok(items.length >= 15, `15 элементов внутри группы (got ${items.length})`); + // Свернуть обратно для чистоты (expand:false = только свернуть) + await clickElement('Товары', { expand: false }); + }); + + await step('switch-tree: «Ещё → Режим просмотра → Дерево» переключает viewMode', async () => { + await clickElement('Ещё'); + await clickElement('Режим просмотра'); + await clickElement('Дерево'); + const t = await readTable(); + log(`after switch: viewMode=${t.viewMode} total=${t.total}`); + assert.equal(t.viewMode, 'tree', 'viewMode переключился в tree'); + }); + + await step('read-tree: readTable в режиме Дерево возвращает _tree состояния', async () => { + const t = await readTable(); + log(`tree rows: ${t.rows?.map(r => `${r['Наименование']}:${r._tree}`).join(' | ')}`); + const groupRows = t.rows.filter(r => /^(Товары|Услуги)$/.test(r['Наименование'] || '')); + assert.equal(groupRows.length, 2, 'обе группы видны в дереве'); + assert.ok(groupRows.every(r => r._tree === 'collapsed' || r._tree === 'expanded'), + '_tree присутствует у каждой группы (collapsed или expanded)'); + }); + + await step('tree-expand: clickElement({expand}) переключает состояние узла', async () => { + // viewMode/expanded сохраняются между сессиями — приводим Товары в collapsed + let t = await readTable(); + let tovary = t.rows.find(r => r['Наименование'] === 'Товары'); + if (tovary?._tree === 'expanded') { + await clickElement('Товары', { expand: false }); // expand:false = свернуть + } + // Теперь явный expand и проверка + const r = await clickElement('Товары', { expand: true }); + log(`clicked: ${JSON.stringify(r.clicked)}`); + assert.equal(r.clicked?.kind, 'gridTreeNode', 'kind=gridTreeNode'); + assert.equal(r.clicked?.toggled, true, 'toggled=true'); + t = await readTable({ maxRows: 30 }); + log(`after tree-expand: total=${t.total}`); + tovary = t.rows.find(row => row['Наименование'] === 'Товары'); + assert.ok(tovary, 'строка Товары присутствует'); + assert.equal(tovary._tree, 'expanded', 'Товары теперь expanded'); + const items = t.rows.filter(row => /^Товар \d+/.test(row['Наименование'] || '')); + assert.ok(items.length >= 15, `видны элементы группы (${items.length})`); + }); + + await step('cleanup: восстановить иерархический список и закрыть форму', async () => { + await clickElement('Ещё'); + await clickElement('Режим просмотра'); + await clickElement('Иерархический список'); + await closeForm(); + }); +}