mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-10 16:14:54 +03:00
feat(web-test): M5-pre #1 — ValueTree + ДеревоНоменклатуры + tree-form smoke
Расширение синтетики: новая обработка ДеревоНоменклатуры с реквизитом
формы Дерево типа ДеревоЗначений и колонками Номенклатура (ссылка,
read-only) + Цена (Number, editable). ПриСозданииНаСервере рекурсивно
обходит Справочник.Номенклатура и заполняет дерево, отражая иерархию
групп/элементов из справочника.
Обработка зарегистрирована в подсистеме Администрирование и в роли
Администратор (Use+View).
Новый smoke 16-tree-form.test.mjs (5 шагов, 17.1s) — покрывает
05-table/edit-form (fillTableRow method:'direct' на FormDataTree-колонке)
и 08-hierarchy/tree-edit (expand узла + правка Цены через index-row):
- setup: navigateLink('Обработка.ДеревоНоменклатуры'), таблица Дерево
- read-roots: 2 корневые группы (_kind:'group'), columns=Номенклатура,Цена
- expand: clickElement('Товары',{expand:true}) → 16 строк (1 + 15)
- tree-edit: fillTableRow({Цена:1500},{row:1}) → method:'direct',
Цена становится '1 500,00' (с non-breaking space 1С)
- cleanup: closeForm
Гэп: fillTableRow с row-by-name ('Товар 01') ловит SyntaxError в JS
eval. Использую row-by-index (TODO в web-test-bugs).
Полный регресс **18/18 зелёный** (8m 9.8s) на порту 9191.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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}' },
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user