mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-10 08:04:56 +03:00
feat(web-test): fillTableRow заполняет ячейку-выбор-из-списка через форму выбора
Поле с кнопкой выбора и обработчиком НачалоВыбора (значение выбирается из программного
списка — например колонка Тип в типовой Консоли запросов) раньше заполнялось plain-paste,
который молча откатывался → ok:true/method:direct (ложный успех). Теперь движок детектит
такую ячейку и выбирает значение из формы выбора.
- dom/grid-edit.mjs: readActiveGridCellScript отдаёт buttonKind активной ячейки
(ref/calc/date/choice по кнопке _DLB/_CB и её классу).
- engine/table/row-fill.mjs v1.20: для kind=choice — F4 → pickFromTypeDialog
(скан/Ctrl+F/OK) → method:choice; если после выбора открылась форма значения,
это составная ячейка (нужен {value,type}). Ветка добавлена в Tab-цикл и directEditPick.
- engine/forms/select-value.mjs v1.21: умный dismiss диалога типов на путях
not_found/multiple — Escape только пока диалог открыт, больше не закрывает
исходную форму слепым Escape×3.
- Стенд: строковая колонка-выбор ТипЗначения (НачалоВыбора → ПоказатьВыборЭлемента)
в ДеревоНоменклатуры; тест 16 покрывает method:choice и негатив not_found.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -812,7 +812,12 @@ export const steps = [
|
||||
{ name: 'Номенклатура', type: 'CatalogRef.Номенклатура', title: 'Номенклатура' },
|
||||
{ name: 'Цена', type: 'Number(15,2)', title: 'Цена' },
|
||||
{ name: 'Картинка', type: 'Boolean', title: 'Картинка' },
|
||||
// Строковая колонка-выбор-из-списка: значение выбирается обработчиком НачалоВыбора
|
||||
// через СписокТипов.ПоказатьВыборЭлемента (как колонка Тип в типовой Консоли запросов).
|
||||
{ name: 'ТипЗначения', type: 'String', title: 'Тип значения' },
|
||||
]},
|
||||
// Список значений для программного выбора (ПоказатьВыборЭлемента).
|
||||
{ name: 'СписокТипов', type: 'ValueList' },
|
||||
],
|
||||
elements: [
|
||||
{ table: 'Дерево', path: 'Дерево', initialTreeView: 'ExpandTopLevel', changeRowSet: true,
|
||||
@@ -824,6 +829,9 @@ export const steps = [
|
||||
{ picField: 'ДеревоКартинка', path: 'Дерево.Картинка', title: 'Картинка', valuesPicture: 'StdPicture.Favorites', loadTransparent: true },
|
||||
// CheckBoxField на тот же булев — для кросс-проверки состояния картинки.
|
||||
{ check: 'ДеревоКартинкаФлаг', path: 'Дерево.Картинка', title: 'Флаг' },
|
||||
// Поле-выбор-из-списка с кнопкой выбора и обработчиком НачалоВыбора.
|
||||
{ input: 'ДеревоТипЗначения', path: 'Дерево.ТипЗначения', title: 'Тип значения',
|
||||
choiceButton: true, on: ['StartChoice'], handlers: { StartChoice: 'ДеревоТипЗначенияНачалоВыбора' } },
|
||||
]},
|
||||
],
|
||||
},
|
||||
@@ -836,6 +844,10 @@ export const steps = [
|
||||
content: `&НаСервере
|
||||
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
|
||||
\tЗаполнитьУровень(Дерево.ПолучитьЭлементы(), Справочники.Номенклатура.ПустаяСсылка());
|
||||
\tСписокТипов.Добавить("Строка");
|
||||
\tСписокТипов.Добавить("Число");
|
||||
\tСписокТипов.Добавить("Дата");
|
||||
\tСписокТипов.Добавить("Булево");
|
||||
КонецПроцедуры
|
||||
|
||||
&НаСервере
|
||||
@@ -877,6 +889,24 @@ export const steps = [
|
||||
\t\tТекущиеДанные.Картинка = НЕ ТекущиеДанные.Картинка;
|
||||
\tКонецЕсли;
|
||||
КонецПроцедуры
|
||||
|
||||
&НаКлиенте
|
||||
Процедура ДеревоТипЗначенияНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
|
||||
\tСтандартнаяОбработка = Ложь;
|
||||
\tОписаниеОповещения = Новый ОписаниеОповещения("ТипЗначенияЗавершениеВыбора", ЭтотОбъект);
|
||||
\tСписокТипов.ПоказатьВыборЭлемента(ОписаниеОповещения, НСтр("ru = 'Выбрать тип'"));
|
||||
КонецПроцедуры
|
||||
|
||||
&НаКлиенте
|
||||
Процедура ТипЗначенияЗавершениеВыбора(ВыбранныйЭлемент, ДополнительныеПараметры) Экспорт
|
||||
\tЕсли ВыбранныйЭлемент = Неопределено Тогда
|
||||
\t\tВозврат;
|
||||
\tКонецЕсли;
|
||||
\tТекущиеДанные = Элементы.Дерево.ТекущиеДанные;
|
||||
\tЕсли ТекущиеДанные <> Неопределено Тогда
|
||||
\t\tТекущиеДанные.ТипЗначения = ВыбранныйЭлемент.Значение;
|
||||
\tКонецЕсли;
|
||||
КонецПроцедуры
|
||||
`,
|
||||
},
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export default async function({ navigateLink, clickElement, closeForm, readTable
|
||||
await step('read-roots: на верхнем уровне видны группы (Товары, Услуги, БольшойСписок)', async () => {
|
||||
const t = await readTable('Дерево');
|
||||
log(`columns=${t.columns?.join(',')} rows=${t.rows?.length}`);
|
||||
assert.deepEqual(t.columns, ['Номенклатура', 'Цена', 'Картинка', 'Флаг'], 'колонки: Номенклатура + Цена + Картинка + Флаг');
|
||||
assert.deepEqual(t.columns, ['Номенклатура', 'Цена', 'Картинка', 'Флаг', 'Тип значения'], 'колонки: Номенклатура + Цена + Картинка + Флаг + Тип значения');
|
||||
assert.equal(t.rows.length, 3, '3 корневые строки');
|
||||
const names = t.rows.map(r => r['Номенклатура']);
|
||||
assert.includes(names, 'Товары', 'есть Товары');
|
||||
@@ -61,6 +61,30 @@ export default async function({ navigateLink, clickElement, closeForm, readTable
|
||||
assert.equal(tovar01['Цена'], '1 500,00', 'Цена обновилась до 1 500,00');
|
||||
});
|
||||
|
||||
await step('choice-cell: fillTableRow задаёт ТипЗначения через форму выбора (НачалоВыбора)', async () => {
|
||||
// Колонка-строка с кнопкой выбора + обработчиком НачалоВыбора → СписокТипов.ПоказатьВыборЭлемента
|
||||
// («Выбрать тип»). Plain-paste тут не годится — движок открывает форму выбора и выбирает из списка.
|
||||
const r = await fillTableRow({ ТипЗначения: 'Число' }, { row: 1 });
|
||||
log(`filled: ${JSON.stringify(r.filled)}`);
|
||||
const cell = r.filled?.find(f => f.field === 'ТипЗначения');
|
||||
assert.ok(cell, 'поле ТипЗначения в результате');
|
||||
assert.equal(cell.ok, true, 'ok=true');
|
||||
assert.equal(cell.method, 'choice', 'method=choice (выбор из списка, не direct)');
|
||||
const t = await readTable('Дерево');
|
||||
const tovar01 = t.rows.find(row => row['Номенклатура'] === 'Товар 01');
|
||||
assert.equal(tovar01['Тип значения'], 'Число', 'ТипЗначения = Число');
|
||||
});
|
||||
|
||||
await step('choice-cell-negative: несуществующий тип → ok:false/not_found (форма не закрывается)', async () => {
|
||||
// not_found гасит только диалог выбора типа (умный dismiss), исходная форма остаётся —
|
||||
// следующие шаги (picture) это подтверждают.
|
||||
const r = await fillTableRow({ ТипЗначения: 'Нетакоготипа' }, { row: 1 });
|
||||
const cell = r.filled?.find(f => f.field === 'ТипЗначения');
|
||||
assert.ok(cell, 'поле ТипЗначения в результате');
|
||||
assert.equal(cell.ok, false, 'ok=false для несуществующего типа');
|
||||
assert.equal(cell.error, 'not_found', 'error=not_found');
|
||||
});
|
||||
|
||||
await step('picture: колонка-картинка (pic:0/\'\') + кросс-проверка чекбоксом', async () => {
|
||||
const t = await readTable('Дерево');
|
||||
const t15 = t.rows.find(r => r['Номенклатура'] === 'Товар 15'); // Цена 1500 > 1000 → иконка
|
||||
|
||||
Reference in New Issue
Block a user