docs(web-test): описать фикстуру _hang и коды выхода в README набора

Фикстура лежит в репозитории, но README о ней не упоминал — а её нельзя
использовать «по интуиции»: ожидаемый результат `1 passed, 1 failed` с кодом
выхода 1, где красный тест означает успех.

Записано: как запускать, какие два условия читать в выводе, когда гонять
(правки пути очистки и жизненного цикла, обновление Playwright — механика
стоит на замеренном поведении библиотеки), чего она стоит (лицензия +
перезапуск браузера в tab-режиме) и чего НЕ ловит (молчаливую поломку logout,
если 1С уйдёт на куки; полумёртвый CDP).

Заодно: коды выхода 2/3 из --global-timeout и актуальный счёт тестов (21→25).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-07-15 17:44:00 +03:00
parent 037d000f20
commit dc8afb402b
+45 -2
View File
@@ -5,7 +5,7 @@ E2E-тесты движка `web-test` (Playwright + изолированная
## Запуск
```bash
# Полный регресс (все 21 тестов)
# Полный регресс (все 25 тестов; фикстура _hang/ в него не входит — см. ниже)
node .claude/skills/web-test/scripts/run.mjs test tests/web-test/
# Один файл
@@ -23,7 +23,7 @@ node .claude/skills/web-test/scripts/run.mjs test tests/web-test/ --grep=multi
URL не передаём позиционно — берётся из `webtest.config.mjs` (`contexts.a.url` = `http://localhost:9191/webtest-runner/ru_RU`). Переопределить можно флагом `--url=<url>`.
Exit code: 0 = все прошли, 1 = есть падения.
Exit code: 0 = все прошли, 1 = есть падения, 2 = сработал `--global-timeout` (отчёт записан, сеансы освобождены), 3 = зависло само сворачивание.
## CLI флаги runner'а
@@ -95,6 +95,49 @@ node .claude/skills/web-test/scripts/run.mjs test tests/web-test/ -- --rebuild-e
| `WEB_TEST_PRESERVE_CLIPBOARD=0` | Отключить save/restore буфера обмена вокруг `pasteText` |
| `WEBTEST_HOOKS_RUNTIME=python` | Использовать py-версии скиллов вместо ps1 (для не-Windows) |
## Фикстура зависания — `_hang/`
Не часть регресса, а **ручная проверка прерывания зависшего теста**. `_`-префикс держит её вне обычного
прогона: `walk()` в `discover.mjs` пропускает `_`-записи внутри каталога, но явно переданный корневой путь
не фильтрует — поэтому `test tests/web-test/` её не видит, а `test tests/web-test/_hang` находит.
```bash
# стенд должен быть уже опубликован — своих _hooks.mjs у фикстуры нет
node .claude/skills/web-test/scripts/run.mjs test tests/web-test/_hang
```
Состав: `01-renderer-block` вешает JS-поток рендерера (`page.evaluate(() => { while(true) {} })`) —
до появления abort-механики такой тест вешал прогон навсегда; `02-survivor` идёт следом и доказывает,
что прогон поехал дальше, а контекст пересоздан со свежим сеансом (то есть лицензия вернулась).
**Ожидаемый результат — `1 passed, 1 failed` и exit code 1. Красный `01` здесь означает успех.**
Читать глазами два условия:
1. `01` упал со строкой `verdict: hang (renderer unresponsive, browser alive)` и
`recovery: context aborted (logout: node, closed: page)`а не завис;
2. `02` зелёный — прогон продолжился и лицензия освободилась.
Автоматической обвязки (spawn раннера + проверка этих условий → 0/1) пока нет, поэтому в CI фикстуру
как обычный набор класть нельзя — код выхода 1 тут штатный.
**Когда гонять:**
- правки пути очистки в `cli/commands/test.mjs` (дедлайны, ветка таймаута) и жизненного цикла в
`engine/core/session.mjs` (`abortContext`, `probeContext`, `disconnect`, `createContext`);
- **обновление Playwright** — механика стоит на замеренном поведении библиотеки: `page.close({runBeforeUnload:false})`
возвращается поверх зависшего `evaluate`, тот отваливается «Target closed», а `cookies()` отвечает при
мёртвом рендерере (пробник). Новая версия может это поменять;
- перед вливанием движковых правок web-test в `dev`.
**Цена:** ~18 с чистого таймаута, намеренное уничтожение контекста, а в `tab`-режиме — ещё и перезапуск
браузера (закрывается последняя вкладка persistent-контекста).
**Слепая зона:** каскад logout считает успехом ответ 2xx. Если 1С однажды начнёт держать сеанс на куке,
а не на `seanceId` в URL, Node-logout продолжит получать 200, фикстура покажет `logout: node` — и поломка
всплывёт только когда утёкшие сеансы упрутся в лимит лицензий. Фикстура этого не ловит.
**Воспроизводит один режим** — заблокированный рендерер. Полумёртвый CDP (сокет жив, браузер не отвечает)
ловится дедлайнами, а не `abortContext`, и здесь не покрыт.
## Артефакты
- `tests/web-test/error-*.png` — скриншоты упавших шагов (auto на `--screenshot=on-failure`)