mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-12 08:54:57 +03:00
07353c416e
Все action-функции теперь возвращают плоский form state с extras —
закрыта последняя аномалия API. Раньше:
- fillFields → {filled, form} (вложенный, документировано в SKILL.md)
- fillTableRow → 3 разных shape в 5 ветках (array | {filled, form} | {filled, notFilled, form}),
при этом документация заявляла плоский — код её игнорировал
Теперь обе функции используют returnFormState({filled, notFilled?}) — тот же
паттерн что у всех action-функций после Phase 1+2 (clickElement, selectValue,
closeForm, filterList и т.д.).
Что закрывает:
1. Тихий баг в production-клиенте C:\WS\projects\titan\tests\helpers\query.mjs
на res.filled?.find() — array-ветки fillTableRow возвращали [{...}] без .filled
→ ошибки заполнения параметров запросов молча пропускались. R1/R2-аналог.
2. Костыли r.filled || r в tests/web-test/05-table.test.mjs (2 места) —
убраны, поскольку polymorphism устранён.
3. Расхождение код ↔ документация в fillTableRow.
4. Внутренний polymorphism в row-fill.mjs: убраны два `if (Array.isArray(more))`
костыля в рекурсивных вызовах самого fillTableRow.
Файлы:
- engine/forms/fill.mjs v1.17 → v1.18 (1 ветка → returnFormState)
- engine/table/row-fill.mjs v1.17 → v1.18 (5 веток + 2 рекурсии)
- tests/web-test/05-table.test.mjs (r.filled || r → r.filled)
- .claude/skills/web-test/SKILL.md (сигнатуры fillFields/fillTableRow + общая
ремарка про плоский return shape в начале раздела Actions)
- docs/web-test-guide.md (строки fillFields/fillTableRow/navigateSection;
общая ремарка в начале раздела «Действия»)
В тестах ни один кейс не обращался к .form.X, blast radius нулевой.
Точечный регресс (03/05/06/07/10/16) и полный регресс 19/19 — зелёные.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
89 lines
4.6 KiB
JavaScript
89 lines
4.6 KiB
JavaScript
export const name = 'Табличная часть: add, edit, delete на Товары накладной';
|
|
export const tags = ['table', 'smoke'];
|
|
export const timeout = 90000;
|
|
|
|
export default async function({ navigateSection, openCommand, clickElement, fillFields, fillTableRow, deleteTableRow, readTable, closeForm, getFormState, assert, step, log }) {
|
|
|
|
await step('add: добавить две строки в Товары через fillTableRow add:true', async () => {
|
|
await navigateSection('Склад');
|
|
await openCommand('Приходная накладная');
|
|
await clickElement('Создать');
|
|
await fillFields({ 'Контрагент': 'ООО Север' });
|
|
|
|
await fillTableRow(
|
|
{ 'Номенклатура': 'Товар 01', 'Количество': '5', 'Цена': '100' },
|
|
{ table: 'Товары', add: true }
|
|
);
|
|
await fillTableRow(
|
|
{ 'Номенклатура': 'Товар 02', 'Количество': '3', 'Цена': '200' },
|
|
{ table: 'Товары', add: true }
|
|
);
|
|
|
|
const t = await readTable({ table: 'Товары' });
|
|
log(`rows after add: ${t.rows?.length}`);
|
|
assert.equal(t.rows?.length, 2, 'Должно быть 2 строки');
|
|
assert.equal(t.rows[0]['Номенклатура'], 'Товар 01', 'Строка 0 = Товар 01');
|
|
assert.equal(t.rows[1]['Номенклатура'], 'Товар 02', 'Строка 1 = Товар 02');
|
|
});
|
|
|
|
await step('edit: изменить количество в строке 0 через fillTableRow row:0', async () => {
|
|
await fillTableRow(
|
|
{ 'Количество': '10' },
|
|
{ table: 'Товары', row: 0 }
|
|
);
|
|
const t = await readTable({ table: 'Товары' });
|
|
log(`row 0 after edit: ${JSON.stringify(t.rows[0])}`);
|
|
assert.equal(t.rows[0]['Количество'], '10,000', 'Количество строки 0 = 10');
|
|
});
|
|
|
|
await step('tab-loop: изменить два числовых поля в строке 1 одним вызовом', async () => {
|
|
const r = await fillTableRow(
|
|
{ 'Количество': '7', 'Цена': '150' },
|
|
{ table: 'Товары', row: 1 }
|
|
);
|
|
log(`tab-loop result: ${JSON.stringify(r)}`);
|
|
const t = await readTable({ table: 'Товары' });
|
|
log(`row 1 after tab-loop: ${JSON.stringify(t.rows[1])}`);
|
|
assert.equal(t.rows[1]['Количество'], '7,000', 'Количество строки 1 = 7');
|
|
assert.equal(t.rows[1]['Цена'], '150,00', 'Цена строки 1 = 150');
|
|
});
|
|
|
|
await step('checkbox: переключить Согласовано в строке 1 через fillTableRow', async () => {
|
|
const r = await fillTableRow(
|
|
{ 'Согласовано': true },
|
|
{ table: 'Товары', row: 1 }
|
|
);
|
|
log(`checkbox result: ${JSON.stringify(r.filled)}`);
|
|
const t = await readTable({ table: 'Товары' });
|
|
log(`row 1 Согласовано='${t.rows[1]['Согласовано']}'`);
|
|
assert.equal(t.rows[1]['Согласовано'], 'true', 'Согласовано должно стать true');
|
|
});
|
|
|
|
await step('clear: очистить ссылочную ячейку Номенклатура через fillTableRow с пустым значением', async () => {
|
|
// Используем строку 0 (Товар 01)
|
|
const r = await fillTableRow(
|
|
{ 'Номенклатура': '' },
|
|
{ table: 'Товары', row: 0 }
|
|
);
|
|
log(`clear result: ${JSON.stringify(r.filled)}`);
|
|
const t = await readTable({ table: 'Товары' });
|
|
log(`row 0 Номенклатура after clear='${t.rows[0]['Номенклатура']}'`);
|
|
assert.equal(t.rows[0]['Номенклатура'], '', 'Номенклатура должна быть очищена (Shift+F4)');
|
|
|
|
// Восстанавливаем Товар 01 чтобы последующий delete мог работать с предсказуемым состоянием
|
|
await fillTableRow(
|
|
{ 'Номенклатура': 'Товар 01' },
|
|
{ table: 'Товары', row: 0 }
|
|
);
|
|
});
|
|
|
|
await step('delete: удалить первую строку', async () => {
|
|
await deleteTableRow(0, { table: 'Товары' });
|
|
const t = await readTable({ table: 'Товары' });
|
|
log(`rows after delete: ${t.rows?.length}, [0]=${t.rows[0]?.['Номенклатура']}`);
|
|
assert.equal(t.rows?.length, 1, 'Должна остаться 1 строка');
|
|
assert.equal(t.rows[0]['Номенклатура'], 'Товар 02', 'Осталась строка Товар 02');
|
|
await closeForm({ save: false });
|
|
});
|
|
}
|