Files
contracts/History/test-results-v1.0.178.md
T

209 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Результаты тестирования — v1.0.178
Дата: 25.06.2026
## Сводка
| Уровень | Тестов | Результат |
|---------|--------|-----------|
| Юнит-тесты (Node.js) | **131** | **✅ 131/131 PASS** |
| `node -c` синтаксис | 6 файлов | ✅ чистый |
| API smoke (curl) | 8 эндпоинтов | ✅ HTTP 200 |
| Аудит кода | — | ✅ 4 бага исправлено |
## Запуск тестов
```bash
cd contractor/deploy && node tests.js
```
Тесты не требуют браузера — все зависимости замоканы (document, window, lucide, crypto, XMLHttpRequest).
---
## Юнит-тесты (131 шт.)
### statusToHTML (21 тест)
Чистая функция: `{ kind, pct?, text?, count?, elapsed? }` → HTML.
| Группа | Тесты |
|--------|-------|
| Граничные | `null`, `undefined`, `{}`, `{ kind: '' }`, `{ kind: 'unknown' }` → пусто |
| `uploading` | pct=0, 75, 100, -5, без pct (→0%) |
| `uploaded` | базовая проверка |
| `unzipping` / `parsing` | текстовые статусы |
| `parsed` | count=5, 0; elapsed='2.3', '0', без elapsed |
| `error` | с текстом, без текста (→дефолт), с пустым текстом (→дефолт) |
### applyParseResult (13 тестов)
Чистая функция: применяет `{ status, element_count, error }` к entry.
| Группа | Тесты |
|--------|-------|
| `parsed` | с elapsed, без elapsed, element_count=0, без element_count |
| `error` | с текстом, без текста (→дефолт "ошибка парсинга") |
| `null` parsed | → `{ kind: 'error', text: 'Неизвестная ошибка' }` |
| Иммутабельность | старые поля entry не затираются |
### reconcileSelection (7 тестов)
Чистая функция: фильтрует `files` по именам из `newFiles`.
| Группа | Тесты |
|--------|-------|
| Норма | 3 файла → 2 осталось, порядок сохранён |
| Пустые | оба массива пусты → `[]` |
| Все совпадают | 1→1 |
| Ни один | 2→0 |
| Дубликаты | Set корректно обрабатывает повторы |
| Иммутабельность | исходный массив не мутирован |
### renderGroupCard (10 тестов)
Чистая HTML-функция: карточка необработанной группы.
| Группа | Тесты |
|--------|-------|
| Базовая | номер, контрагент, типы документов, дата, data-gi, кнопка «Сравнить» |
| Нет «✓ Готово» | для необработанной группы |
| `compare.status === 'running'` | кнопка disabled |
| Без контрагента | заглушка «контрагент не определён» |
| Неизвестный doc_type | выводится как есть |
| Пустые документы | карточка рендерится, кнопка есть |
| Типы | contract→договор, supplement→допсоглашение, specification→спецификация |
### renderGroupCardDone (5 тестов)
Чистая HTML-функция: карточка обработанной группы.
| Группа | Тесты |
|--------|-------|
| Заголовок | ✓ Готово (12.5с), стрелка сворачивания |
| bodyHTML | вставлен в карточку |
| data-gi | на заголовке для обработчика клика |
| Типы | specification→спецификация |
### renderUnresolvedCard (3 теста)
Чистая HTML-функция: карточка нераспознанных файлов.
| Группа | Тесты |
|--------|-------|
| Заголовок | «Не распознано» |
| Причина 1 | «нет базового договора №999» (есть parent_number) |
| Причина 2 | «ошибка классификации: LLM error» (classify_status=failed) |
### applyCompareEvent (14 тестов)
Чистая функция: мутирует `sections` по SSE-событиям.
| Группа | Тесты |
|--------|-------|
| `extract_start` | создаёт секцию с filename, status='extracting' |
| `llm_done` | обновляет status, ops_count, mode, time_s |
| `applied` | сохраняет summary, ops |
| `extract_error` | на существующей секции → status='error' |
| `extract_error` | на НЕсуществующей → создаёт новую с ошибкой |
| `apply_error` | аналогично extract_error |
| `applied` без summary | не падает |
| `applied` с пустыми ops | не падает |
| Неизвестный тип | секция НЕ создаётся (не падает) |
| `llm_done` на несуществующей | не падает |
### renderCompareSectionHeader (5 тестов)
Чистая функция: заголовок секции сравнения.
| Статус | Проверка |
|--------|----------|
| `extracting` | ⏳ + filename |
| `llm_done` | ✓ + filename + ops_count + mode + time_s |
| `error` | ✗ + filename + текст ошибки |
### renderCompareOpsTable (6 тестов)
Чистая функция: HTML-таблица операций.
| Группа | Тесты |
|--------|-------|
| ADD/DELETE | правильные CSS-классы (diff-added, diff-deleted) |
| Данные | имя услуги, цена, количество, сумма, дата |
| Пустые ops | таблица рендерится с пустым tbody |
| null new_row | пустые ячейки (не падает) |
| MERGE (неизв.) | без классов diff-* |
### renderCompareSectionBody (7 тестов)
Чистая функция: тело секции (summary + таблица).
| Группа | Тесты |
|--------|-------|
| Граничные | null, {}, status='llm_done' → пусто |
| applied | +3 ~1 -0 ?2, UPDATE → diff-changed |
| Без unresolved | нет знака ? |
| Отрицательные summary | рендерится без ошибок |
| Частичный new_row | нет undefined в выводе |
### escHtml (7 тестов)
| Вход | Выход |
|------|-------|
| `null`, `undefined` | `''` |
| `'hello'` | `'hello'` |
| `'<script>'` | `'&lt;script&gt;'` |
| `'a&b'` | `'a&amp;b'` |
| `'"quote"'` | `'&quot;quote&quot;'` |
| `123` | `'123'` |
---
## API Smoke Tests (curl)
| Эндпоинт | Код |
|----------|-----|
| `GET /` | 200 |
| `POST /api/cleanup` | 200 |
| `GET /static/state.js` | 200 |
| `GET /static/app_utils.js` | 200 |
| `GET /static/files.js` | 200 |
| `GET /static/groups.js` | 200 |
| `GET /static/compare.js` | 200 |
| `GET /static/app.js` | 200 |
---
## Баги, найденные и исправленные при аудите
| # | Баг | Файл | Исправление |
|---|-----|------|-------------|
| 1 | `SITE_URL` — неиспользуемая переменная | app.js:8 | Удалена |
| 2 | `UNZIP_URL` — двойное объявление | app.js:6-7 | Удалён дубль |
| 3 | `promptEditor` — двойное объявление | app.js:467,470 | Удалён дубль |
| 4 | `llmStart` — неиспользуемая после Фазы 3 | app.js:301 | Удалена |
---
## Структура модулей (финальная)
```
contractor/deploy/
├── state.js (70 строк) Центральное состояние
├── app_utils.js (120 строк) escHtml, formatSize, removeFile, ...
├── files.js (480 строк) upload, parse, ZIP, renderFiles, syncDB
├── groups.js (230 строк) loadGroupsAction, renderGroups, renderGroupCard
├── compare.js (230 строк) startCompareSSE, applyCompareEvent, renderCompareOpsTable
├── app.js (450 строк) Оркестратор: render, classify, compare, prompts, chat
└── tests.js (400 строк) 131 юнит-тест
```
Загрузка в `index.cfm`: state → app_utils → files → groups → compare → app.
---
## Команды для регресса
```bash
# Синтаксис всех модулей
cd contractor/deploy && for f in state.js app_utils.js files.js groups.js compare.js app.js; do node -c "$f" || echo "FAIL: $f"; done
# Юнит-тесты
node tests.js
# Деплой JS на ВМ
scp -i ~/.ssh/naeel_vm_id_ed25519 *.js naeel@5.172.178.213:/home/naeel/contracts/
# Дым API
curl -s --max-time 5 -o /dev/null -w "%{http_code}\n" https://contracts.kube5s.ru/static/state.js
```