Files
cc-1c-skills/tests/web-test/03-fillfields.test.mjs
T
Nick Shirokov 62e864e474 feat(web-test): M5-pre #3 — textEdit:false поле + 03-fillfields/direct-edit-form
Расширение синтетики: реквизит Поставщик типа CatalogRef.Контрагенты
добавлен в шапку ПриходнаяНакладная. Элемент формы Поставщик скомпилирован
с textEdit:false (новый DSL ключ form-compile v1.21 из коммита 32bf9c1):
ручной ввод запрещён, селект-кнопки нет, выбор только через форму выбора
по pick-кнопке.

Новый шаг 03-fillfields/direct-edit-form (~7s) — fillFields на Поставщик
('ООО Юг') возвращает method:'form', минуя обычные paste/typeahead/dropdown
ветки. fillFields внутренне детектит textEdit:false и сразу идёт через
форму выбора (selectValue path).

Полный регресс **18/18 зелёный** (8m 40.6s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 16:11:46 +03:00

179 lines
9.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export const name = 'fillFields: text, checkbox, date, dropdown, reference';
export const tags = ['fillfields', 'smoke'];
export const timeout = 120000;
const findField = (state, name) => state.fields?.find(f => f.name === name || f.label === name);
export default async function({ navigateSection, openCommand, clickElement, fillFields, fillTableRow, selectValue, filterList, closeForm, getFormState, assert, step, log }) {
await step('text+checkbox+date+dropdown: fillFields на Номенклатура', async () => {
await navigateSection('Склад');
await openCommand('Номенклатура');
await clickElement('Товары', { dblclick: true }); // войти в папку
await clickElement('Товар 01', { dblclick: true });
const result = await fillFields({
'Артикул': 'TEST-001',
'Активен': false, // Boolean → CheckBoxField, toggle
'ДатаПоступления': '15.05.2026', // date
'ВидНоменклатуры': 'Услуга', // EnumRef dropdown
});
log('methods: ' + result.filled.map(f => `${f.field}=${f.method}`).join(', '));
for (const f of result.filled) {
assert.ok(f.ok, `fillField "${f.field}" должен вернуть ok=true`);
}
const state = await getFormState();
assert.equal(findField(state, 'Артикул')?.value, 'TEST-001', 'Артикул text');
assert.equal(findField(state, 'Активен')?.value, false, 'Активен checkbox=false');
assert.equal(findField(state, 'ДатаПоступления')?.value, '15.05.2026', 'ДатаПоступления');
assert.equal(findField(state, 'ВидНоменклатуры')?.value, 'Услуга', 'ВидНоменклатуры dropdown');
await closeForm({ save: false });
});
await step('reference-dropdown: Организация → CatalogRef.Организации (quickChoice=true)', async () => {
await navigateSection('Склад');
await openCommand('Приходная накладная');
await clickElement('Создать');
const fillRes = await fillFields({
'Организация': 'Альфа',
});
log('reference method: ' + fillRes.filled[0]?.method);
assert.ok(fillRes.filled[0]?.ok, 'Организация fillField должна сработать');
const state = await getFormState();
const org = findField(state, 'Организация');
log(`Организация value='${org?.value}'`);
assert.includes(org?.value || '', 'Альфа', 'Организация должна показать выбранное значение');
await closeForm({ save: false });
});
await step('clear: fillFields пустым значением очищает текстовое поле', async () => {
await navigateSection('Склад');
await openCommand('Контрагенты');
await clickElement('ООО Север', { dblclick: true });
const before = await getFormState();
const phoneBefore = findField(before, 'Телефон')?.value;
log(`phone before clear='${phoneBefore}'`);
const r = await fillFields({ 'Телефон': '' });
log('clear method: ' + r.filled[0]?.method);
assert.ok(r.filled[0]?.ok, 'clear должен вернуть ok=true');
assert.equal(r.filled[0]?.method, 'clear', 'method должен быть clear (Shift+F4)');
const state = await getFormState();
assert.equal(findField(state, 'Телефон')?.value, '', 'Телефон должен быть пустым');
await closeForm({ save: false });
});
await step('reference-non-quickchoice: fillFields на Контрагент (quickChoice=false)', async () => {
// Поле имеет DLB+CB → fillFields идёт через fillReferenceField (method=dropdown/typeahead).
// Чистый method='form' путь требует поля без DLB (hasPick && !hasSelect) — в синтетике
// такого поля нет, поэтому проверяем сам факт корректного заполнения через DLB.
await navigateSection('Склад');
await openCommand('Приходная накладная');
await clickElement('Создать');
const r = await fillFields({ 'Контрагент': 'ООО Север' });
log('reference method: ' + r.filled[0]?.method);
assert.ok(r.filled[0]?.ok, 'fillFields на Контрагент должен сработать');
assert.ok(['dropdown', 'typeahead', 'form'].includes(r.filled[0]?.method),
`method=${r.filled[0]?.method} должен быть один из dropdown|typeahead|form`);
const state = await getFormState();
const v = findField(state, 'Контрагент')?.value || '';
log(`Контрагент value='${v}'`);
assert.includes(v, 'Север', 'Контрагент должен содержать "Север"');
await closeForm({ save: false });
});
await step('radio: КатегорияЦены (RadioButtons) через fillFields, СпособУчёта (Tumbler) через clickElement', async () => {
// Tumbler-представление не парсится fillFields как radio-поле (см.
// upload/web-test-bugs.md пункт 5). Но варианты тумблера видны в
// state.buttons и кликаются через clickElement — покрываем через него.
await navigateSection('Склад');
await openCommand('Номенклатура');
await filterList('Товар 02');
await clickElement('Товар 02', { dblclick: true });
// RadioButtons — fillFields с method=radio
const result = await fillFields({ 'Категория цены': 'Оптовая' });
log('RadioButtons method: ' + result.filled[0]?.method + ', value: ' + result.filled[0]?.value);
assert.ok(result.filled[0]?.ok, 'КатегорияЦены fillField должна сработать');
assert.equal(result.filled[0]?.method, 'radio', 'КатегорияЦены должна использовать method=radio');
assert.includes(result.filled[0]?.value || '', 'Оптовая', 'КатегорияЦены = Оптовая');
// Tumbler — варианты «По среднему» / «ФИФО» доступны как buttons
const before = await getFormState();
const tumblerButtons = (before.buttons || [])
.map(b => b.name || b)
.filter(n => n === 'По среднему' || n === 'ФИФО');
log('Tumbler buttons: ' + tumblerButtons.join(', '));
assert.equal(tumblerButtons.length, 2, 'Tumbler должен показывать оба варианта в buttons[]');
await clickElement('ФИФО');
log('Tumbler clicked: ФИФО');
await closeForm({ save: false });
});
await step('composite: selectValue с {type} в шапке и ТЧ накладной', async () => {
// ПриходнаяНакладная.Источник — составной тип:
// CatalogRef.Контрагенты + CatalogRef.Номенклатура + CatalogRef.Организации
// fillFields без type→ошибка с подсказкой «specify the type»;
// selectValue('Источник', value, {type:'Контрагенты'}) выбирает тип в диалоге.
await navigateSection('Склад');
await openCommand('Приходная накладная');
await clickElement('Создать');
// Шапка: выбор Контрагента в составном поле
const headRes = await selectValue('Источник', 'ООО Север', { type: 'Контрагенты' });
log('header: type=' + headRes.selected?.type + ' method=' + headRes.selected?.method);
assert.equal(headRes.selected?.method, 'form', 'composite header → method=form');
assert.equal(headRes.selected?.type, 'Контрагенты', 'type=Контрагенты выбран');
const state1 = await getFormState();
const headField = state1.fields?.find(f => f.name === 'Источник');
assert.equal(headField?.value, 'ООО Север', 'значение в шапке установилось');
// ТЧ: добавить строку, выбрать тип Организация (квик-чойс — без формы выбора)
await clickElement('Добавить');
const rowRes = await fillTableRow(
{ Источник: { value: 'Альфа', type: 'Организации' } },
{ row: 0 },
);
log('row: ' + JSON.stringify(rowRes.filled?.[0]));
assert.equal(rowRes.filled?.[0]?.ok, true, 'composite row → ok');
assert.equal(rowRes.filled?.[0]?.type, 'Организации', 'выбран тип Организации в ТЧ');
await closeForm({ save: false });
});
await step('direct-edit-form: textEdit:false → fillFields method=form', async () => {
// ПриходнаяНакладная.Поставщик — обычный CatalogRef.Контрагенты, но
// элемент формы с textEdit:false: ручной ввод запрещён, выбор только
// через форму выбора (не через paste/typeahead/dropdown).
await navigateSection('Склад');
await openCommand('Приходная накладная');
await clickElement('Создать');
const r = await fillFields({ 'Поставщик': 'ООО Юг' });
log('Поставщик method=' + r.filled[0]?.method);
assert.equal(r.filled[0]?.ok, true, 'Поставщик заполнен');
assert.equal(r.filled[0]?.method, 'form',
'textEdit:false принуждает к method=form (минуя paste/typeahead/dropdown)');
const state = await getFormState();
const p = state.fields?.find(f => f.name === 'Поставщик');
assert.equal(p?.value, 'ООО Юг', 'значение Поставщик установилось');
await closeForm({ save: false });
});
}