docs(tests): описать все поля тест-кейса в README

Таблица «Все поля кейса» отставала от раннера: не были описаны idempotent,
runtimeOnly, skipValidation, а expect ограничивался упоминанием files/
stdoutContains/stdoutNotContains — preserves и структура preRun не
документировались вовсе.

Из-за таких пробелов формат кейса приходится выяснять по коду — а это ровно
тот способ, который однажды дал 9 кейсов meta-edit с несуществующим ключом:
тесты зелёные, навык no-op, снэпшот фиксирует исходник.

Добавлено (сверено с runner.mjs и с реальными кейсами):
- idempotent, runtimeOnly, skipValidation в основную таблицу;
- таблица ключей expect + вложенная таблица preserves (file/bom/eol/encoding/
  finalNewline/noCR13) с пометкой, что preserves и эталон дополняют друг друга:
  первый следит за байтовым стилем, второй за структурой;
- формы шагов preRun (прогон навыка и writeFile).

editFile намеренно не описан — это шаг интеграционных тестов, не preRun кейса.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-07-25 15:35:02 +03:00
co-authored by Claude Opus 5
parent 3b5444e69d
commit 769b4d3dbd
+37 -2
View File
@@ -227,10 +227,45 @@ ibcmd-проход автоматически `○ skipped`, если рядом
| `setup` | нет | Переопределение setup из `_skill.json` | | `setup` | нет | Переопределение setup из `_skill.json` |
| `outputPath` | нет | Относительный путь для навыков с `-OutputPath` | | `outputPath` | нет | Относительный путь для навыков с `-OutputPath` |
| `args_extra` | нет | Массив дополнительных CLI-аргументов | | `args_extra` | нет | Массив дополнительных CLI-аргументов |
| `preRun` | нет | Массив шагов подготовки (создание объектов и т.п.) | | `preRun` | нет | Массив шагов подготовки (см. ниже) |
| `expect` | нет | Дополнительные проверки: `files`, `stdoutContains` (строка/массив), `stdoutNotContains` (строка/массив) | | `expect` | нет | Дополнительные проверки (см. ниже) |
| `expectError` | нет | `true` или строка — ожидается ошибка | | `expectError` | нет | `true` или строка — ожидается ошибка |
| `noSnapshot` | нет | Непустая строка с причиной — кейс объявляет, что эталон не нужен (см. «Эталоны») | | `noSnapshot` | нет | Непустая строка с причиной — кейс объявляет, что эталон не нужен (см. «Эталоны») |
| `idempotent` | нет | `true` — повторный прогон с теми же аргументами должен дать байт-в-байт тот же `workDir` |
| `runtimeOnly` | нет | `"powershell"` / `"python"` — кейс имеет смысл только на одном порте, на другом `○ skipped` |
| `skipValidation` | нет | `true` — не запускать `postValidate` из `_skill.json` (только при `--with-validation`) |
### Ключи `expect`
| Ключ | Описание |
|---|---|
| `files` | Массив путей относительно `workDir` — каждый должен существовать после прогона |
| `stdoutContains` | Строка или массив строк — все должны присутствовать в stdout |
| `stdoutNotContains` | Строка или массив строк — ни одной не должно быть в stdout |
| `preserves` | Объект (или массив объектов) — байтовые свойства файла, которые навык обязан сохранить |
`preserves` проверяет то, что снэпшот-сравнение нормализует и потому увидеть не может:
| Ключ | Описание |
|---|---|
| `file` | Путь к файлу относительно `workDir` (обязателен) |
| `bom` | `true`/`false` — наличие UTF-8 BOM |
| `eol` | `"crlf"` / `"lf"` |
| `encoding` | Ожидаемое значение в XML-декларации, напр. `"UTF-8"` |
| `finalNewline` | `true`/`false` — перевод строки в конце файла |
| `noCR13` | `true` — в выходе не должно быть литерала `&#13;` |
`preserves` и эталон **дополняют** друг друга: первый следит за байтовым стилем файла, второй — за
структурой содержимого. Наличие одного не отменяет необходимости другого.
### Шаги `preRun`
Массив шагов, выполняемых до запуска проверяемого навыка:
| Форма шага | Описание |
|---|---|
| `{ "script": "<навык>/scripts/<файл>", "input": {...}, "args": { "-Flag": "{inputFile}" } }` | Прогон другого навыка для подготовки фикстуры. Плейсхолдеры: `{inputFile}`, `{workDir}` |
| `{ "writeFile": { "path": "<путь>", "content": "<строка или объект>" } }` | Записать произвольный файл в `workDir` (объект сериализуется в JSON) |
## Эталоны (snapshots) ## Эталоны (snapshots)