mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-10 16:14:54 +03:00
feat(web-test): hasMore.above для динамических списков через turn-кнопки
Раньше для динамических списков (catalog/journal/register) определялся
только hasMore.below (через scrollH>clientH). Направление выше было
неопределимо потому что у дин-списков нет видимого scrollbar widget'а.
Однако у большинства дин-списков 1С рендерит панель пагинации
#vertButtonScroll_<gridId> (сосед грида) с 4 кнопками: data-home
(в начало), data-up (предыдущая страница), data-down (следующая),
data-end (в конец). Класс "disabled" на кнопке = направление недоступно.
readTableScript и snapshotGridScript теперь сначала смотрят на эти
кнопки (если виджет видим), и только потом фолбачатся на scrollbar
tracks для табчастей и scrollHeight для редких случаев без обоих
виджетов.
Проверено на bp-demo Контрагенты:
- root (6 групп помещаются): {above:false, below:false}
- Покупатели at top: {above:false, below:true}
- after End: {above:true, below:false}
- after Home: {above:false, below:true}
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+32
-13
@@ -260,37 +260,56 @@ console.log('Расшифровка:', JSON.stringify(drilldown.rows));
|
||||
- `_selected: true` — строка выделена (подсвечена). Используйте с `clickElement({ modifier: 'ctrl'|'shift' })` для проверки мультиселекции
|
||||
- На объекте результата: `hierarchical: true`, `viewMode: 'tree'`
|
||||
|
||||
#### clickElement — клик по ячейке SpreadsheetDocument
|
||||
**Виртуализация и `hasMore`.** 1С виртуализирует и динамические списки, и табличные части — в DOM лежит только окно видимых строк. Поля `total` / `shown` — это размер DOM-окна, а **не** размер коллекции. Чтобы понять, есть ли строки за пределами окна, используйте `hasMore`:
|
||||
|
||||
Для расшифровки отчётов первый аргумент `clickElement` принимает объект `{ row, column }` вместо текста. Координаты соответствуют выводу `readSpreadsheet()`:
|
||||
```js
|
||||
const t = await readTable();
|
||||
// t.hasMore = { above: false, below: true } — открыли список, есть строки ниже
|
||||
// t.hasMore = { above: true, below: false } — пролистали в конец
|
||||
// t.hasMore = { above: false, below: false } — всё помещается / нет страниц
|
||||
```
|
||||
|
||||
`hasMore.below` присутствует всегда. `hasMore.above` тоже обычно есть — определяется по кнопкам пагинации (`vertButtonScroll`, есть у большинства дин-списков) или треку скроллбара (у табчастей). Отсутствует только в редких случаях, когда у грида нет ни кнопок, ни видимого скроллбара — тогда трактуйте отсутствие как «неизвестно».
|
||||
|
||||
#### clickElement — клик по ячейке (spreadsheet или грид формы)
|
||||
|
||||
Первый аргумент `clickElement` принимает объект `{ row, column }` вместо текста. Маршрутизация автоматическая: если на форме отрисован SpreadsheetDocument (отчёт) — кликаем туда (drill-down), иначе — по ячейке грида (табчасть, список). Параметр `table: 'ИмяГрида'` принудительно указывает грид, если на форме одновременно есть отчёт и таблицы.
|
||||
|
||||
**SpreadsheetDocument (drill-down отчёта).** Координаты соответствуют выводу `readSpreadsheet()`:
|
||||
|
||||
```js
|
||||
const report = await readSpreadsheet();
|
||||
// report.data[0] = { 'К1': 'Материалы строительные', 'К6': '150 000' }
|
||||
|
||||
// По индексу строки данных + имя колонки
|
||||
await clickElement({ row: 0, column: 'К6' }, { dblclick: true });
|
||||
|
||||
// По значению ячейки в строке (fuzzy match)
|
||||
await clickElement({ row: { 'К1': 'Материалы' }, column: 'К6' }, { dblclick: true });
|
||||
|
||||
// Строка итогов
|
||||
await clickElement({ row: 'totals', column: 'К6' }, { dblclick: true });
|
||||
await clickElement({ row: 0, column: 'К6' }, { dblclick: true }); // по индексу
|
||||
await clickElement({ row: { 'К1': 'Материалы' }, column: 'К6' }, { dblclick: true }); // по фильтру
|
||||
await clickElement({ row: 'totals', column: 'К6' }, { dblclick: true }); // итоги
|
||||
await clickElement('150 000', { dblclick: true }); // fallback: по тексту в iframe'ах
|
||||
```
|
||||
|
||||
Текстовый поиск тоже работает — если элемент не найден в основном DOM, `clickElement` ищет в SpreadsheetDocument iframe'ах:
|
||||
**Грид формы (табчасть документа, список каталога/журнала).** Колонка вне viewport — авто-скролл по горизонтали (с учётом frozen-колонок). `scroll: true | number` включает reveal-loop через PageDown для filter-row за пределами DOM-окна:
|
||||
|
||||
```js
|
||||
await clickElement('150 000', { dblclick: true }); // найдёт ячейку в отчёте
|
||||
await clickElement({ row: 0, column: 'Количество' }, { table: 'Товары', dblclick: true });
|
||||
await clickElement({ row: { 'Номенклатура': 'Бумага' }, column: 'Цена' }, { table: 'Товары' });
|
||||
await clickElement(
|
||||
{ row: { 'Номер': '0000-000601' }, column: 'Сумма' },
|
||||
{ table: 'Реализации', scroll: true } // PageDown loop, лимит по умолчанию 50
|
||||
);
|
||||
```
|
||||
|
||||
**Подводные камни:**
|
||||
- `row: <число>` — индекс в **текущем DOM-окне**, не абсолютный (1С виртуализирует длинные списки). Для произвольной строки в длинном списке — `row: { col: val }` + `scroll: true`.
|
||||
- `scroll: true` идёт только **вниз** (PageDown). Для вверх — `page.keyboard.press('Home')` через `getPage()` или сначала `filterList`.
|
||||
- На дубликаты при фильтре — первая подходящая строка. Уточняйте фильтр для disambiguation.
|
||||
|
||||
### Действия
|
||||
|
||||
Все action-функции возвращают **плоский form state** (как `getFormState()`) с action-specific extras (`clicked`, `selected`, `filled`, `notFilled`, `closed`, `opened`, `navigated`, `deleted`, `filtered`, `unfiltered`). Errors всегда на верхнем уровне `.errors` — exec-wrapper автоматически throw'ает на soft validation errors (`modal`/`balloon`).
|
||||
|
||||
| Функция | Описание | Возвращает |
|
||||
|---------|----------|------------|
|
||||
| `clickElement(text, {dblclick?, modifier?})` | Клик по кнопке/ссылке/строке. `{dblclick: true}` для открытия, `{modifier: 'ctrl'\|'shift'}` для мультиселекции. Первый аргумент может быть `{row, column}` для клика по ячейке SpreadsheetDocument (см. выше) | form state или `{ submenu }` |
|
||||
| `clickElement(text, {dblclick?, modifier?, table?, scroll?})` | Клик по кнопке/ссылке/строке. `{dblclick: true}` для открытия, `{modifier: 'ctrl'\|'shift'}` для мультиселекции. Первый аргумент может быть `{row, column}` для клика по ячейке spreadsheet или грида формы (`table` форсит грид; `scroll: true \| number` включает reveal-loop через PageDown — см. выше) | form state или `{ submenu }` |
|
||||
| `fillFields({name: value})` | Заполнить поля (текст, чекбокс, радио, ссылки, DCS-фильтры). Пустое значение (`''`/`null`) = очистка | form state с `filled` |
|
||||
| `selectValue(field, search, opts?)` | Выбрать из справочника. search: текст, `{поле: значение}` или `''`/`null` для очистки. `{ type }` для составного типа | form state с `selected` |
|
||||
| `fillTableRow(fields, {tab?, add?, row?})` | Заполнить строку. Значение: строка, `{ value, type }` для составного типа, `''`/`null` для очистки | form state с `filled` (per-field ошибки как items `ok: false`, см. ниже) + `notFilled?` |
|
||||
|
||||
Reference in New Issue
Block a user