docs(web-test): пользовательский гайд регресса + skill-инструкция regress.md

- docs/web-test-regression-guide.md — пользовательские сценарии работы
  с моделью для покрытия прикладного решения регрессом (русский, по
  аналогии с web-test-recording-guide.md): структура tests/<app-name>/,
  диалоги с моделью, пример организации покрытия, отчёты Allure +
  categories.json.
- .claude/skills/web-test/regress.md — инструкция модели по написанию
  регрессионного набора: разведка (метаданные + живой проход через exec),
  layout по фичам, готовые шаблоны (CRUD/document/DCS/multi-user/repro),
  severity, anti-patterns, failure triage, _allure/ конвенция.
- SKILL.md — указатель на regress.md в конце файла (рядом с recording).
- docs/web-test-runner-spec.md → upload/ (был внутренним планом
  разработки, не пользовательской документацией).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-05-13 20:25:44 +03:00
parent b992cd11c5
commit f4748d76af
4 changed files with 828 additions and 1051 deletions
+391
View File
@@ -0,0 +1,391 @@
# Регрессионное тестирование прикладного решения
Навык `/web-test` умеет не только разово выполнить сценарий в браузере, но и сопровождать прикладное решение полноценным набором автотестов: каждый тест — отдельный файл, с шагами, проверками, тегами, отчётом и видеозаписью падений. После каждой правки конфигурации модель прогоняет весь набор и показывает, что ожидаемо ведёт себя как раньше, а что сломалось.
```
правка конфигурации → загрузка → обновление → публикация → прогон тестов → отчёт
```
Это про прикладное решение в целом, не про разовую проверку одной формы. Для разовых сценариев («открой накладную, проверь сумму») по-прежнему удобнее интерактивный режим из [web-test-guide.md](web-test-guide.md).
## Предусловия
- База опубликована через Apache (`/web-publish`).
- Установлен Node.js 18+, зависимости подняты: `cd .claude/skills/web-test/scripts && npm install`.
- ffmpeg — нужен только если хотите видеозапись прогона как доказательство падения. Без него падения фиксируются скриншотами. Установка описана в [web-test-recording-guide.md](web-test-recording-guide.md).
## Как это устроено
Набор тестов живёт в каталоге `tests/` вашего проекта. Каждое прикладное решение — отдельная подпапка. Внутри подпапки:
- `_hooks.mjs` — подготовка стенда (восстановление базы, публикация) и общая очистка после прогона. Необязателен.
- `webtest.config.mjs` — адрес базы и набор пользователей (например, кладовщик и менеджер для процессов согласования). Необязателен — если в проекте один пользователь и один URL, можно обойтись без него.
- Сами тесты — файлы `*.test.mjs`, сгруппированные по функциональным папкам.
```
tests/
моя-конфигурация/
_hooks.mjs
webtest.config.mjs
01-вход/
01-открытие-базы.test.mjs
02-контрагенты/
01-создание.test.mjs
02-правка-телефона.test.mjs
03-поступление-товаров/
01-оформление.test.mjs
02-проведение.test.mjs
04-отчёт-остатки/
01-формирование.test.mjs
05-согласование/
01-полный-цикл.test.mjs
```
Порядок выполнения — по алфавиту, поэтому удобно префиксовать папки и файлы номерами. Это даёт предсказуемый сценарий: сначала вход, потом справочники, потом документы, потом отчёты, в конце — процессы с несколькими пользователями.
## Быстрый старт
Самый короткий путь от нуля до зелёного теста — попросить модель пройти ваш сценарий руками и зафиксировать его как тест:
```
> Покрой регрессом справочник Контрагенты в моей конфигурации.
> Нужны проверки: создание, правка телефона, удаление.
```
Что сделает модель:
1. Соберёт информацию о справочнике через `/meta-info` и `/form-info` — посмотрит реквизиты и форму элемента, чтобы знать правильные имена полей.
2. Подключится к опубликованной базе в интерактивном режиме и **руками пройдёт** каждый сценарий — создание, правка, удаление. Это нужно, чтобы зафиксировать настоящие имена кнопок, увидеть, какие диалоги показывает 1С, понять, требуется ли подтверждение сохранения.
3. Зафиксирует пройденный сценарий как файл `tests/<ваша-конфигурация>/02-контрагенты/01-создание.test.mjs`.
4. Запустит его и покажет результат.
При следующих прогонах ничего этого делать не нужно — модель просто запустит готовый набор.
## Сценарии работы с моделью
### Покрытие регрессом доработанного объекта
```
> Я добавил в справочник Номенклатура реквизит "Цена" и "Активен".
> Покрой это регрессом — создание, редактирование, фильтрация по активности
```
Модель:
- посмотрит структуру справочника и формы (через `/meta-info`, `/form-info`);
- интерактивно проверит, как ведут себя новые поля в браузере;
- сгенерирует 2-3 тестовых файла под папкой `02-номенклатура/`;
- прогонит — покажет, что зелёное, что красное.
### Тест процесса с несколькими пользователями
```
> Сделай тест для процесса согласования приходных накладных.
> Кладовщик создаёт накладную, менеджер утверждает,
> кладовщик видит обновлённый статус
```
Модель настроит в `webtest.config.mjs` двух пользователей (с разными URL базы — например, `app-clerk` и `app-manager`), напишет тест, который оркестрирует переключение между ними, и положит его в `05-согласование/`.
```js
export const contexts = ['кладовщик', 'менеджер'];
export default async function({ кладовщик, менеджер, step, assert }) {
await step('Кладовщик создаёт накладную', async () => {
await кладовщик.navigateSection('Склад');
await кладовщик.openCommand('Приходные накладные');
await кладовщик.clickElement('Создать');
// ...
});
await step('Менеджер утверждает', async () => {
await менеджер.navigateSection('Согласование');
// ...
});
// ...
}
```
Учтите ограничение по лицензиям 1С: каждый одновременно открытый пользователь — это занятая клиентская лицензия. Если в наборе много многопользовательских тестов, а на стенде лицензий впритык, прогоны начнут спотыкаться на «свободных лицензий не осталось». Модель освобождает сессии между тестами автоматически (закрывает контексты после процессного теста), но если стенд ограничен — закладывайте это в планирование набора: один-два многопользовательских сценария вместо десяти.
### Воспроизведение ошибки тестом
```
> При проведении накладной без заполненного контрагента у нас не появляется
> ошибка валидации, документ просто проводится с пустым контрагентом — это баг.
> Зафиксируй это падающим тестом
```
Модель воспроизведёт сценарий, напишет тест с проверкой «должна быть ошибка», получит красный — потом, когда вы поправите конфигурацию и попросите перепрогнать, тест станет зелёным. Это документирует ожидаемое поведение в виде кода.
### Прогон регресса после изменений
```
> Я обновил расширение, накатил в базу. Прогони регресс
```
Модель запустит весь набор, дождётся завершения и расскажет:
- сколько тестов прошло, сколько упало, сколько пропущено;
- по каждому упавшему — что именно сломалось (название шага, сообщение об ошибке, ссылка на скриншот);
- классифицирует падения: это ошибка в самом тесте (нужно поправить тест), ошибка в приложении (баг, который вы внесли изменением), или нестабильность стенда (Apache не ответил вовремя, лицензия не освободилась).
```
> Прогони только тесты по контрагентам с подробным отчётом
```
Запустит подмножество — фильтр по тегу или папке, с записью JSON-отчёта.
### Подготовка автономного стенда
Если вы хотите, чтобы регресс можно было запустить «с нуля» — даже на чистой машине без подготовленной базы, — модель настроит автоматическую подготовку стенда:
```
> Сделай, чтобы перед прогоном тестов база восстанавливалась из эталона,
> а после прогона публикация снималась
```
Это пишется один раз в файле `_hooks.mjs`: при запуске тестов запускается подготовка (через навыки `/db-create`, `/db-load-xml`, `/web-publish`), а после — очистка. Внутри предусмотрено кэширование: если ничего не менялось со прошлого прогона, повторная подготовка занимает доли секунды.
## Пример организации покрытия
Допустим, у нас условное прикладное решение «Учёт поступлений товаров» — справочники контрагентов и номенклатуры, документ приходной накладной, отчёт остатков, процесс согласования с двумя пользователями. Логично организовать набор так:
```
tests/учёт-поступлений/
_hooks.mjs # подготовка: восстановление базы + публикация
webtest.config.mjs # URL базы, контексты кладовщика и менеджера
01-вход/
01-открытие-базы.test.mjs # базовая работоспособность: вход проходит, разделы видны
02-навигация-по-разделам.test.mjs # обход всех разделов конфигурации
02-контрагенты/
01-создание.test.mjs # создание, проверка появления в списке
02-редактирование.test.mjs # правка реквизита, проверка сохранения
03-удаление.test.mjs # удаление с подтверждением
03-номенклатура/
01-создание.test.mjs
02-фильтр-по-активности.test.mjs # быстрая фильтрация списка
04-поступление-товаров/
01-оформление.test.mjs # заполнение шапки и табличной части
02-проведение.test.mjs # проведение документа, проверка движений
03-отмена-проведения.test.mjs
04-валидация-обязательных.test.mjs # негативный тест: пустой контрагент → ошибка
05-отчёт-остатки/
01-формирование.test.mjs
02-отбор-по-складу.test.mjs
03-расшифровка.test.mjs # переход из ячейки отчёта в исходный документ
06-согласование/
01-полный-цикл.test.mjs # многопользовательский тест
```
Принципы:
- **Папки — по бизнес-функции**, не по типу метаданных. Лучше `04-поступление-товаров/` (что делает пользователь), чем `документы/` (что лежит в дереве конфигурации).
- **Цифровые префиксы** — на папке и на файле. Гарантируют, что сначала отработают базовые проверки (вход, справочники), потом сложные (документы, отчёты, процессы). При падении базы остальное и так не пройдёт — нет смысла занимать стенд получасом.
- **Один файл — одна логически связанная история.** Не «всё про контрагентов в одном файле», а «отдельно создание, отдельно правка, отдельно удаление». Когда падает — сразу видно, какой именно сценарий сломан.
- **Негативные тесты тоже есть.** «Документ без контрагента не проводится» — такой же важный регресс, как и позитивный сценарий, особенно после правок в обработчиках проверки заполнения.
- **Процессные тесты — в конце.** Они самые хрупкие (зависят от двух сессий, лицензий, синхронизации) и самые длинные. Если упадут — у вас уже есть данные от предыдущих тестов.
## Анатомия одного теста
Пользователь, как правило, тест не пишет — генерирует модель. Но прочитать и поправить полезно уметь. Стандартный файл выглядит так:
```js
export const name = 'Создание контрагента';
export const tags = ['контрагенты', 'базовая-проверка'];
export const timeout = 60000;
export default async function({
navigateSection, openCommand, clickElement, fillFields,
readTable, closeForm, assert, step
}) {
await step('Открыть список контрагентов', async () => {
await navigateSection('Продажи');
await openCommand('Контрагенты');
});
await step('Создать нового контрагента', async () => {
await clickElement('Создать');
await fillFields({ 'Наименование': 'ТД Тест', 'ИНН': '7707083893' });
await clickElement('Записать и закрыть');
});
await step('Убедиться, что элемент появился в списке', async () => {
const t = await readTable();
assert.tableHasRow(t, r => r['Наименование'] === 'ТД Тест');
});
}
```
Что здесь есть:
- **`name`** — человекочитаемое имя теста. Появится в отчёте.
- **`tags`** — теги для фильтрации. Можно прогонять не весь набор, а только нужные: `--tags=контрагенты`.
- **`timeout`** — сколько максимум тест может идти. По умолчанию 30 секунд, для длинных сценариев увеличиваем.
- **Тело теста** — функция, которая получает API браузера (см. [SKILL.md](../.claude/skills/web-test/SKILL.md)) плюс `assert` и `step`.
- **`step('имя', async () => {...})`** — обёртка шага. Имена шагов попадают в отчёт, при падении видно, какой именно шаг сломался.
- **`assert.*`** — проверки. `assert.tableHasRow`, `assert.equal`, `assert.ok` и т.д. Если проверка не выполнилась — тест считается упавшим.
Имена шагов и теста — по-русски, описательные. Они показываются и в консоли, и в отчётах.
## Запуск и отчёты
### Простой прогон
```
> Прогони регресс
```
Модель запустит весь набор, дождётся, покажет сводку:
```
✓ Открытие базы (2.1s)
✓ Создание контрагента (8.4s)
✗ Проведение приходной накладной (12.7s)
└ Заполнить табличную часть (5.2s)
Не найден столбец "Цена" в табличной части "Товары"
скриншот: tests/учёт-поступлений/error-shot.png
23 пройдено, 1 упал, 0 пропущено (3 мин 42 с)
```
### Подробный отчёт
```
> Прогони регресс и сохрани подробный отчёт
```
Модель добавит флаг записи отчёта (JSON или Allure) — потом по нему можно листать историю прогонов, видеть длительности шагов, открывать прикреплённые скриншоты.
Allure — стандартный визуальный отчёт с категориями падений, графиками, таймлайном. Чтобы посмотреть отчёт после прогона:
```bash
# Allure CLI устанавливается отдельно (npm install -g allure-commandline)
allure serve allure-results
```
### Категории падений в Allure
Без дополнительной настройки Allure складывает все упавшие тесты в один общий список «Defects». Если в прогоне упало 15 тестов, не сразу понятно, что из этого — пятнадцать разных проблем или одна и та же ошибка (например, нехватка лицензии на стенде), которая зацепила пятнадцать тестов подряд.
Чтобы Allure группировал падения по причинам, рядом с тестами кладётся каталог `_allure/` с файлом `categories.json`. Подчёркивание в имени каталога — чтобы он не воспринимался как папка с тестами; раннер копирует его содержимое в отчёт.
```
tests/моя-конфигурация/
_allure/
categories.json # классификация падений
environment.properties # необязательно: URL, версия 1С, ветка git
executor.json # необязательно: метаданные сборки CI
_hooks.mjs
01-вход/
...
```
`categories.json` — это список регулярных выражений, по которым ошибка теста относится к той или иной группе:
```json
[
{ "name": "Нехватка лицензий 1С",
"matchedStatuses": ["failed", "broken"],
"messageRegex": ".*Не обнаружено свободной лицензии.*" },
{ "name": "Ошибка приложения 1С",
"matchedStatuses": ["failed"],
"messageRegex": ".*(ВызватьИсключение|В поле введены некорректные данные|Произошла ошибка).*" },
{ "name": "Элемент не найден",
"matchedStatuses": ["failed"],
"messageRegex": ".*(clickElement|fillFields|selectValue).*not found.*" },
{ "name": "Превышен лимит времени теста",
"matchedStatuses": ["failed", "broken"],
"messageRegex": "Timeout \\(\\d+ms\\)" },
{ "name": "Несовпадение ожидания и факта",
"matchedStatuses": ["failed"],
"messageRegex": "(Expected|AssertionError).*" }
]
```
Когда вы попросите модель в первый раз настроить регресс, она положит шаблонный `categories.json` со стандартными классами. По мере того как вы будете находить новые типичные причины падений (например, специфичные для вашего расширения тексты ошибок), категории дополняются.
В виджете «Categories» итогового отчёта вы увидите примерно так:
```
Нехватка лицензий 1С — 12 падений
Ошибка приложения 1С — 2 падения
Несовпадение ожидания и факта — 1 падение
```
— и сразу понятно, что 12 падений — это один стенд-баг, а двумя «ошибками приложения» нужно разобраться по существу.
Помимо `categories.json` в каталог `_allure/` можно положить ещё два стандартных файла:
- **`environment.properties`** — список `ключ=значение` (URL базы, версия платформы 1С, имя ветки git, номер сборки). Покажется в отчёте в виджете «Environment». Полезно, когда регресс гоняется на нескольких стендах или после каждого билда — видно, на чём именно был получен результат. Этот файл удобно генерировать прямо в подготовке стенда (`_hooks.mjs`), а не держать статичной копией.
- **`executor.json`** — метаданные системы сборки: ссылка на Jenkins-задачу, идентификатор запуска GitHub Actions и т.д. Нужен только если регресс запускается на сервере сборки. При локальном прогоне ничего класть не надо.
### Прогон части набора
```
> Прогони только тесты по поступлениям товаров
> Прогони только базовые проверки
> Прогони только упавший вчера тест с проведением накладной
```
Модель выберет нужное подмножество — по папке, по тегу или по имени теста.
### Принудительная пересборка стенда
Если хотите, чтобы перед прогоном база восстановилась с нуля:
```
> Прогони регресс с полной пересборкой стенда
```
Это передаст в подготовку флаг типа `--rebuild-stand``_hooks.mjs` пересоздаст базу из эталона. Полезно после крупных правок или если подозреваете, что предыдущие прогоны загрязнили данные.
## Что делать, когда тест упал
Модель проанализирует падение и отнесёт его к одной из трёх категорий:
1. **Ошибка в самом тесте.** Например, переименовали реквизит — тест ищет старое имя поля. Решение: модель обновит тест.
2. **Ошибка в приложении.** Это и есть то, ради чего регресс существует: что-то поменялось в конфигурации, и сценарий, который раньше работал, теперь не отрабатывает. Модель опишет, что именно произошло, со скриншотом и трассировкой стека 1С, если ошибка была серверной.
3. **Нестабильность стенда.** Apache не ответил, не освободилась лицензия, база отвалилась. Это лечится не правкой теста, а починкой подготовки стенда в `_hooks.mjs` или, реже, повторным прогоном с одним повтором.
Просите модель не «исправь упавший тест», а «разберись с падением» — иначе она может молча подкрутить ожидание под текущее поведение, замаскировав настоящий баг.
## Полезные подробности
### Тестовые данные
В прикладном решении обычно нужны какие-то стартовые данные: пара контрагентов, номенклатура, заведённые организации. Их кладём не в каждый тест, а один раз в подготовку стенда (`_hooks.mjs`) — после восстановления базы загружаются эталонные данные, на которых работают все тесты.
Если конкретному тесту нужны свои данные (например, документ, который мы будем редактировать), он создаёт их сам в начале и убирает в конце.
### Имена документов и уникальность
Тесты прогоняются многократно. Если тест создаёт документ «Накладная-Тест», следующий прогон может натолкнуться на старую запись. Решение — добавлять к имени метку времени:
```js
const метка = 'Тест-' + Date.now();
await fillFields({ 'Комментарий': метка });
// ...
const t = await readTable();
assert.tableHasRow(t, r => r['Комментарий'] === метка);
```
Модель это делает автоматически, но если правите тест руками — держите в голове.
### Видео при падении
Можно включить запись видео всех тестов — тогда при падении прикладывается не только скриншот, но и MP4 со всей сессией:
```
> Прогони регресс с записью видео
```
Размер прогона при этом растёт (на 2-3 минутах теста выходит 5-10 МБ), но при отладке сложного падения видео экономит кучу времени.
### Многоязычные конфигурации
Если у вас есть конфигурация с командами и реквизитами на нескольких языках, тесты пишутся под один язык (как правило, тот, в котором ведётся работа в проде). При смене языка интерфейса в браузере тесты не пройдут — модель видит другие подписи кнопок.
## Где смотреть дальше
- API браузера, которое вызывают тесты — [SKILL.md](../.claude/skills/web-test/SKILL.md).
- Подробная инструкция для модели по написанию тестов (на английском, технический документ) — [.claude/skills/web-test/regress.md](../.claude/skills/web-test/regress.md).
- Интерактивный режим без тестов — [web-test-guide.md](web-test-guide.md).
- Запись видеоинструкций — [web-test-recording-guide.md](web-test-recording-guide.md).