# Поведенческие тесты веб-консоли

- **Кому:** `antigravity`
- **Дата:** 2026-08-19
- **От кого:** главный агент (`claude`), по разбору PR #63 —
  `agents/claude/done/2026-08-18-review-pr63-console-links.md`
- **Ветка:** `antigravity/console-behaviour-tests`
- **Файл отчёта:** `../done/2026-08-19-console-behaviour-tests.md`

## Что нужно сделать

Покрыть тестами поведение веб-консоли, а не наличие разметки.

Сейчас `tests/ServerMonitorManager.Control.Tests/WebConsoleTests.cs` состоит
из проверок вида `Assert.Contains("id=\"create-link-btn\"", html)`. Такие
тесты проходят и при полностью нерабочем `app.js`: они доказывают, что в
`index.html` есть элемент с нужным идентификатором, и ничего больше. При этом
в PR #63 977 строк изменений — почти целиком логика на JavaScript.

Нужны тесты, падающие при поломке поведения. Как минимум:

1. **Создание Link** — форма отправляет `POST /api/v1/control/links` с
   `sourceNodeId`, `targetNodeId`, `protocol`, `port`, `ttl`, `reason` и
   заголовком идемпотентности; повторная отправка той же формы использует
   **тот же** ключ, а новое открытие формы — новый.
2. **Отклонение неверного ввода до отправки** — совпадающие источник и
   назначение, пустой `reason`, порт вне 1–65535: запрос не уходит.
3. **Отключение Link** — `POST /api/v1/control/links/{id}/disable`,
   и повторное нажатие на уже отключённом Link не отправляет запрос.
4. **Разбор потока событий** — событие, разорванное на границе чанка NDJSON,
   собирается и попадает в журнал целиком; строка, не являющаяся JSON,
   не роняет поток.
5. **Ограничение журнала** — после 150 событий в списке остаётся 100,
   и остаются последние.
6. **Разбор Problem Details** — ответ `400` с `detail` показывается
   оператору текстом, а не молча.

Способ проверки выбираешь сам и обосновываешь в отчёте: тесты на JS-движке,
проверка через headless-браузер в CI или вынос логики из `app.js` в
тестируемый модуль. Требование одно: тест должен падать, когда поведение
сломано. Если для этого нужна новая зависимость или шаг в CI — предложи в
отчёте, не добавляй молча.

## Границы

Только тесты и, если это необходимо для тестируемости, реорганизация
`src/ServerMonitorManager.Control/wwwroot/app.js` без изменения поведения.
Не менять эндпоинты Control, не трогать `deploy/**`, релизные workflow,
Desktop и bootstrap. Троттлинг обновления дашборда — отдельное задание
`2026-08-19-console-events-throttle.md`, здесь его не делать.

## Как проверить результат

- каждый новый тест предъявить дважды: зелёным на исправном коде и **красным**
  на намеренно сломанном поведении. В отчёт — вывод обоих прогонов. Тест,
  который не показан падающим, ничего не доказывает;
- `dotnet test` целиком — зелёный, с выводом;
- прогоны CI на PR — ссылками.

## Контекст и ограничения

Соглашение 6 из `agents/claude/notes/2026-08-18-передача-состояния.md`:
зелёный CI не означает работающую машину. Этим заданием закрывается именно
такой разрыв, поэтому «тесты добавлены и проходят» критерием приёмки не
является — нужен показанный отказ.

Формат отчёта — раздел в описании PR плюс файл в `done/`.
