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

8.7 KiB
Raw Blame History

Результаты тестирования — v1.0.178

Дата: 25.06.2026

Сводка

Уровень Тестов Результат
Юнит-тесты (Node.js) 131 131/131 PASS
node -c синтаксис 6 файлов чистый
API smoke (curl) 8 эндпоинтов HTTP 200
Аудит кода 4 бага исправлено

Запуск тестов

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.


Команды для регресса

# Синтаксис всех модулей
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