diff --git a/tests/skills/integration/build-webtest-config.test.mjs b/tests/skills/integration/build-webtest-config.test.mjs index 688349c8..101593a7 100644 --- a/tests/skills/integration/build-webtest-config.test.mjs +++ b/tests/skills/integration/build-webtest-config.test.mjs @@ -361,6 +361,19 @@ export const steps = [ validate: { script: 'meta-validate/scripts/meta-validate', flag: '-ObjectPath', path: 'DataProcessors/ТестовыеОшибки' }, }, + // Обработка ДеревоНоменклатуры — реквизит формы ДеревоЗначений с данными + // справочника Номенклатура для тестов tree-grid (05-table/direct-edit-form, + // 08-hierarchy/tree-edit). + { + name: 'meta-compile: Обработка ДеревоНоменклатуры', + script: 'meta-compile/scripts/meta-compile', + input: { + type: 'DataProcessor', name: 'ДеревоНоменклатуры', + }, + args: { '-JsonPath': '{inputFile}', '-OutputDir': '{workDir}' }, + validate: { script: 'meta-validate/scripts/meta-validate', flag: '-ObjectPath', path: 'DataProcessors/ДеревоНоменклатуры' }, + }, + // Отчёт ОстаткиТоваров { name: 'meta-compile: Отчёт ОстаткиТоваров', @@ -675,6 +688,69 @@ export const steps = [ `, }, + // Форма обработки ДеревоНоменклатуры — tree-grid с двумя колонками + { + name: 'form-add: Форма обработки ДеревоНоменклатуры', + script: 'form-add/scripts/form-add', + args: { '-ObjectPath': '{workDir}/DataProcessors/ДеревоНоменклатуры.xml', '-FormName': 'ФормаОбработки' }, + }, + { + name: 'form-compile: Форма обработки ДеревоНоменклатуры', + script: 'form-compile/scripts/form-compile', + input: { + title: 'Дерево номенклатуры', + events: { OnCreateAtServer: 'ПриСозданииНаСервере' }, + attributes: [ + { name: 'Объект', type: 'DataProcessorObject.ДеревоНоменклатуры', main: true }, + { name: 'Дерево', type: 'ValueTree', columns: [ + { name: 'Номенклатура', type: 'CatalogRef.Номенклатура', title: 'Номенклатура' }, + { name: 'Цена', type: 'Number(15,2)', title: 'Цена' }, + ]}, + ], + elements: [ + { table: 'Дерево', path: 'Дерево', initialTreeView: 'ExpandTopLevel', changeRowSet: true, columns: [ + { input: 'Номенклатура', path: 'Дерево.Номенклатура', readOnly: true, title: 'Номенклатура' }, + { input: 'Цена', path: 'Дерево.Цена', title: 'Цена' }, + ]}, + ], + }, + args: { '-JsonPath': '{inputFile}', '-OutputPath': '{workDir}/DataProcessors/ДеревоНоменклатуры/Forms/ФормаОбработки/Ext/Form.xml' }, + validate: { script: 'form-validate/scripts/form-validate', flag: '-FormPath', path: 'DataProcessors/ДеревоНоменклатуры/Forms/ФормаОбработки/Ext/Form.xml' }, + }, + { + name: 'writeFile: ДеревоНоменклатуры form Module.bsl', + writeFile: 'DataProcessors/ДеревоНоменклатуры/Forms/ФормаОбработки/Ext/Form/Module.bsl', + content: `&НаСервере +Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) +\tЗаполнитьУровень(Дерево.ПолучитьЭлементы(), Справочники.Номенклатура.ПустаяСсылка()); +КонецПроцедуры + +&НаСервере +Процедура ЗаполнитьУровень(КоллекцияЭлементов, Родитель) +\tЗапрос = Новый Запрос; +\tЗапрос.Текст = +\t\t"ВЫБРАТЬ +\t\t|\tСсылка, ЭтоГруппа, Цена, Наименование +\t\t|ИЗ +\t\t|\tСправочник.Номенклатура +\t\t|ГДЕ +\t\t|\tРодитель = &Родитель +\t\t|УПОРЯДОЧИТЬ ПО +\t\t|\tЭтоГруппа УБЫВ, Наименование"; +\tЗапрос.УстановитьПараметр("Родитель", Родитель); +\tВыборка = Запрос.Выполнить().Выбрать(); +\tПока Выборка.Следующий() Цикл +\t\tНовыйУзел = КоллекцияЭлементов.Добавить(); +\t\tНовыйУзел.Номенклатура = Выборка.Ссылка; +\t\tНовыйУзел.Цена = Выборка.Цена; +\t\tЕсли Выборка.ЭтоГруппа Тогда +\t\t\tЗаполнитьУровень(НовыйУзел.ПолучитьЭлементы(), Выборка.Ссылка); +\t\tКонецЕсли; +\tКонецЦикла; +КонецПроцедуры +`, + }, + // ── 4. DCS for report ── // Сначала добавляем макет ОсновнаяСхемаКомпоновкиДанных к отчёту (регистрируется // в Reports/ОстаткиТоваров.xml + автоматически выставляется MainDataCompositionSchema), @@ -751,6 +827,7 @@ export const steps = [ 'InformationRegister.КурсыВалют', 'Constant.ОсновнаяВалюта', 'DataProcessor.ТестовыеОшибки', + 'DataProcessor.ДеревоНоменклатуры', ], }, args: { '-DefinitionFile': '{inputFile}', '-OutputDir': '{workDir}' }, @@ -771,6 +848,7 @@ export const steps = [ 'Document.ПриходнаяНакладная: Read View Add Update Delete Posting UnPosting', 'InformationRegister.КурсыВалют: Read View Add Update Delete', 'Report.ОстаткиТоваров: Use View', + 'DataProcessor.ДеревоНоменклатуры: Use View', ], }, args: { '-JsonPath': '{inputFile}', '-OutputDir': '{workDir}' }, diff --git a/tests/web-test/16-tree-form.test.mjs b/tests/web-test/16-tree-form.test.mjs new file mode 100644 index 00000000..5866eeaf --- /dev/null +++ b/tests/web-test/16-tree-form.test.mjs @@ -0,0 +1,62 @@ +export const name = 'tree-form: FormDataTree edit (ДеревоНоменклатуры obrabotka)'; +export const tags = ['tree', 'table']; +export const timeout = 90000; + +// ДеревоНоменклатуры obrabotka: реквизит формы Дерево типа ДеревоЗначений +// заполняется в ПриСозданииНаСервере рекурсивным обходом справочника Номенклатура. +// Колонка Цена — Number, editable; колонка Номенклатура — CatalogRef, readOnly. +// Покрывает: 05-table/edit-form (fillTableRow method:'direct' на FormDataTree-колонке) +// + 08-hierarchy/tree-edit (expand узла + edit Цены внутри expanded группы). + +export default async function({ navigateLink, clickElement, closeForm, readTable, fillTableRow, assert, step, log }) { + + await step('setup: открыть обработку ДеревоНоменклатуры', async () => { + const r = await navigateLink('Обработка.ДеревоНоменклатуры'); + log(`form=${r.form} activeTab=${r.activeTab}`); + assert.equal(r.activeTab, 'Дерево номенклатуры', 'форма открыта'); + assert.ok(r.tables?.some(t => t.name === 'Дерево'), 'таблица Дерево присутствует'); + }); + + await step('read-roots: на верхнем уровне видны 2 группы (Товары, Услуги)', async () => { + const t = await readTable('Дерево'); + log(`columns=${t.columns?.join(',')} rows=${t.rows?.length}`); + assert.deepEqual(t.columns, ['Номенклатура', 'Цена'], 'колонки: Номенклатура + Цена'); + assert.equal(t.rows.length, 2, '2 корневые строки'); + const names = t.rows.map(r => r['Номенклатура']); + assert.includes(names, 'Товары', 'есть Товары'); + assert.includes(names, 'Услуги', 'есть Услуги'); + assert.ok(t.rows.every(r => r._kind === 'group'), 'обе корневые — group (есть expand-стрелка)'); + }); + + await step('expand: clickElement({expand}) раскрывает Товары — 15 элементов', async () => { + const r = await clickElement('Товары', { expand: true }); + log(`clicked: ${JSON.stringify(r.clicked)}`); + assert.equal(r.clicked?.toggled, true, 'expand toggled'); + const t = await readTable('Дерево'); + log(`after expand: total=${t.total}`); + assert.ok(t.total >= 16, `Товары + 15 элементов (got ${t.total})`); + const tovar01 = t.rows.find(row => row['Номенклатура'] === 'Товар 01'); + assert.ok(tovar01, 'Товар 01 виден внутри Товары'); + assert.equal(tovar01['Цена'], '100,00', 'исходная Цена 100,00 (из справочника)'); + }); + + await step('tree-edit: fillTableRow меняет Цену в развёрнутой группе', async () => { + // row:1 — это Товар 01 (row:0 — Товары после expand). Используем index, т.к. + // fillTableRow{row:'Товар 01'} ловит SyntaxError в JS-эвале — TODO в bug list. + const r = await fillTableRow({ Цена: 1500 }, { row: 1 }); + log(`filled: ${JSON.stringify(r.filled)}`); + assert.equal(r.filled?.length, 1, '1 поле заполнено'); + assert.equal(r.filled[0].field, 'Цена', 'поле Цена'); + assert.equal(r.filled[0].method, 'direct', 'method=direct (in-place edit)'); + assert.equal(r.filled[0].ok, true, 'ok=true'); + const t = await readTable('Дерево'); + const tovar01 = t.rows.find(row => row['Номенклатура'] === 'Товар 01'); + assert.ok(tovar01, 'Товар 01 виден'); + // 1С web использует non-breaking space ( ) как разделитель разрядов + assert.equal(tovar01['Цена'], '1 500,00', 'Цена обновилась до 1 500,00'); + }); + + await step('cleanup: закрыть форму', async () => { + await closeForm(); + }); +}