Files
enduro-trails/docs/work-items/ET-005/13-test-report.md
claude-bot 3f6e7ae284
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 4s
CI / lint (pull_request) Successful in 4s
CI / test (pull_request) Successful in 5s
CI / build (push) Successful in 3s
CI / build (pull_request) Successful in 1s
tester(ET): auto-commit from tester run_id=12
2026-05-21 21:29:11 +00:00

16 KiB
Raw Blame History

type, work_item_id, version, status, tester, date, commit_tested, verdict
type work_item_id version status tester date commit_tested verdict
test-report ET-005 1 pass agent:tester 2026-05-21 2fe5cfe PASS

Test Report — ET-005

Verdict: PASSstage:ready-to-deploy

Полный регресс зелёный: pytest 31 passed, 4 skipped, 0 failed; JS-юнит-тесты units.js 20/20 pass; e2e Playwright TP-01…TP-05 6/6 pass (0 JS-ошибок на странице); lint чистый; тест-окружение отвечает 200. Блокирующих багов (P0/P1) не найдено.

Весь тест-план 04-test-plan.yaml (TP-01…TP-05) исполнен в реальном браузере — в отличие от ET-002, e2e не блокирован. Все 4 acceptance- критерия покрыты и не нарушены.

Окружение

  • Дата прогона: 2026-05-21
  • Ветка: feature/ET-005-
  • Код-коммит: 2fe5cfe (feat(web): переключатель единиц измерения расстояний (км/мили); источник — 12-review.md)
  • HEAD: d32ad8f (reviewer(ET): auto-commit ...) — поверх кода только артефакт ревью, изменений кода нет; тестировалось рабочее дерево
  • Python: 3.12.13
  • pytest: 8.3.3 (plugins: asyncio-1.3.0, anyio-4.13.0)
  • Node: v22.22.2 (node --test)
  • Playwright: 1.60.0, Chromium headless (chromium-headless-shell v1223)
  • ruff: установлен по pyproject.toml [dev]
  • test-env: https://openclaw.mva154.duckdns.org/enduro/ → HTTP 200

Healthcheck

Среда URL Код
local dev http://localhost:5556/health connection refused (dev не поднят — ОК, прогон оффлайн)
test https://openclaw.mva154.duckdns.org/enduro/ 200

ET-005 — фронтенд-изменение. В test задеплоен предыдущий код, поэтому healthcheck подтверждает только живость окружения; фича попадёт в test штатной перевыкладкой src/web/ после merge (см. 07-infra-requirements.md §7). e2e-прогон выполнен против кода ветки, поднятого локально статическим сервером (python -m http.serversrc/web/), не против test-окружения. На prom ничего не запускалось.

Команды запуска

# Unit + integration (эквивалент make test)
python -m pytest tests/ -v

# JS behavioral unit-тесты units.js (TP-01..TP-04, AC-2, AC-3)
node --test tests/unit/units.test.js

# e2e (TP-01..TP-05): локальная раздача src/web + Playwright/Chromium
python -m http.server 8777 --directory src/web &
python /tmp/et005_e2e.py

# Lint
ruff check src/ tests/

Результаты pytest

python -m pytest tests/ -v31 passed, 4 skipped, 1 warning in 0.62s

Файл Тестов PASS SKIP
integration/test_routing_barriers.py 7 3 4
unit/test_health.py 1 1 0
unit/test_poi_toggle.py (ET-002, регресс) 10 10 0
unit/test_unit_toggle.py (ET-005) 17 17 0
Итого 35 31 4

ET-005 — test_unit_toggle.py (17/17 PASS):

Тест Покрывает Результат
test_units_module_exists наличие src/web/units.js (ADR-0001 п.2) PASS
test_units_module_public_api контракт window.Units (ADR-0001 п.3) PASS
test_units_module_constants KM_TO_MI=0.621371, distance_unit, дефолт km PASS
test_units_module_exports_for_browser_and_node window.Units + module.exports PASS
test_unit_toggle_present_in_html кнопка km/mi в попапе (ФТ-1, AC-1) PASS
test_unit_toggle_reuses_seg_control_component переиспользование .seg-control (R8) PASS
test_units_js_loaded_before_app_js порядок скриптов (R7, ADR-0001 п.2) PASS
test_unit_toggle_has_styles стили .terrain-unit-row (AC-4) PASS
test_app_js_unit_functions_defined onUnitToggle/syncUnitToggleUI/onUnitChange PASS
test_app_js_has_et005_block_markers блок-маркеры >>> ET-005 ... >>> PASS
test_app_js_single_unitchange_subscription ровно одна подписка unitchange (ADR п.6) PASS
test_app_js_uses_centralized_formatter форматирование через Units.formatDistance PASS
test_app_js_distance_helpers_delegate_to_units хелперы делегируют в units.js (R1) PASS
test_app_js_scale_bar_is_unit_aware scale-bar учитывает единицу (R3) PASS
test_app_js_gpx_export_stays_metric GPX-экспорт остаётся метрическим (R6) PASS
test_app_js_restores_unit_choice_on_load восстановление выбора при загрузке (AC-3) PASS
test_js_unit_tests_pass запуск units.test.js через Node-раннер PASS

4 SKIP — интеграционные тесты роутинга ET-001 (test_routing_barriers.py::test_route_*); требуют поднятого OSRM, недоступного в окружении тестера (штатный skip, чтобы CI без инфраструктуры не падал). ET-005 — фронтенд-изменение, на роутинг не влияет; к регрессу не относится.

Предупреждение PytestDeprecationWarning (asyncio_default_fixture_loop_scope) — внешняя зависимость pytest-asyncio, к ET-005 отношения не имеет, не блокирует.

Результаты JS unit-тестов units.js

node --test tests/unit/units.test.js# tests 20, # pass 20, # fail 0

Тесты исполняют реальный src/web/units.js (сброс require.cache + инъекция моков window/document/localStorage перед каждым тестом). Покрыты TP-01…TP-04, AC-2, AC-3, граница 1000 м, недоступный localStorage, валидация setUnit(), публикация неймспейса, единый разделитель «запятая» (R4), точность по умолчанию.

Результаты e2e (Playwright / Chromium) — TP-01…TP-05

Прогон в headless-Chromium против кода ветки, поднятого локально (src/web/ через http.server). Взаимодействие — через реальные DOM-клики по кнопкам попапа (onUnitToggle срабатывает по inline onclick). Пересчёт видимых расстояний верифицирован на живой масштабной линейке карты (#scale-zoom-bar), которую перерисовывает оркестратор onUnitChange().

TC Сценарий Факт Результат
TP-01 дефолт после очистки localStorage getUnit()='km', кнопка «км» .active, «мили» нет, localStorage=пусто, formatDistance(12345)='12,3 км' PASS
TP-02 переключение в мили getUnit()='mi', «мили» .active, localStorage='mi', formatDistance(12345)='7,7 ми', scale-bar '55 km'→'35 mi' PASS
TP-03 persistence после reload после перезагрузки getUnit()='mi', «мили» .active PASS
TP-04 возврат в км getUnit()='km', «км» .active, localStorage='km', scale-bar снова '55 km' PASS
TP-05 mobile responsive 375px обе кнопки видимы и в пределах вьюпорта (km x=166 w=57, mi x=226 w=57), клик переключает PASS
NFR-perf переключение < 100 мс клик + пересчёт всех поверхностей = 0,5 мс PASS

Итог e2e: 6/6 PASS. На странице не зафиксировано ни одной JS-ошибки (pageerror за весь прогон — none).

Покрытие тест-плана (04-test-plan.yaml)

TC Тип Исполнение Статус
TP-01 e2e Playwright + JS-тест units.test.js PASS
TP-02 e2e Playwright (scale-bar km→mi) + JS-тест PASS
TP-03 e2e Playwright (reload) + JS-тест PASS
TP-04 e2e Playwright (scale-bar mi→km) + JS-тест PASS
TP-05 e2e Playwright, viewport 375×667 PASS

Исполнено и пройдено: 5/5 тест-кейсов.

Соответствие Acceptance Criteria

AC Описание Источник проверки Статус
AC-1 Кнопка km/mi в панели, показывает выбор, клик переключает e2e TP-01 (км active по умолчанию), TP-02/TP-04 (клик переключает класс .active), test_unit_toggle_present_in_html PASS
AC-2 Пересчёт всех расстояний, коэф. 0.621371, округление до 1 знака e2e TP-02 (scale-bar 55 km→35 mi, formatDistance(12345)=12,3 км→7,7 ми), units.test.js (KM_TO_MI, точность 1 знак), test_units_module_constants PASS
AC-3 Сохранение/восстановление из localStorage, дефолт km e2e TP-01 (дефолт km, localStorage пуст), TP-02 (localStorage='mi'), TP-03 (выживает reload) PASS
AC-4 Кнопка не перекрывает элементы, mobile, переключение < 100мс e2e TP-05 (375px, кнопки в пределах вьюпорта, кликабельны), NFR-perf (0,5 мс ≪ 100 мс), test_unit_toggle_has_styles PASS

Все 4 критерия имеют поведенческое покрытие в реальном браузере; ни один не нарушен. Коэффициент 0.621371 и округление до 1 знака подтверждены и unit-тестами на реальном units.js, и e2e-конвертацией.

Найденные баги

P0 (блокирующие)

Нет.

P1 (критические)

Нет.

P2 (важные)

T-01 (= R-01 из 12-review.md) — переключение единиц сбрасывает выбор варианта связки. В режиме связки onUnitChange() вызывает renderLinkCards(linkRoutes), которая всегда подсвечивает «Вариант 1»; выбранный пользователем вариант 2/3 теряется при каждом переключении км/мили. Дефект унаследован из ревью (зафиксирован reviewer'ом как R-01/P2). Тестером в этом прогоне не воспроизводился инструментально — режим связки требует построенного маршрута и поднятого OSRM, недоступного в окружении (см. 4 SKIP). Расстояния при этом пересчитываются корректно, ФТ-3 ТЗ формально выполнено; дефект ограничен UX режима связки. P2 — merge/деплой не блокирует. Действие: dev — поправить в этом же PR (ввести activeLinkIdx) либо осознанно вынести в техдолг.

P3 (косметика / наблюдения)

  1. (= R-02 из 12-review.md) Масштабная линейка в режиме «mi» использует латиницу и точку ('0.5 mi') вместо запятой и русских подписей units.js ('0,5 ми'). Это пред-существующее поведение scale-bar (в режиме «km» и раньше было '30 km'), ET-005 лишь расширил тот же стиль на мили — регрессии нет. e2e подтвердил: scale-bar корректно меняет суффикс km↔mi. Косметика, не блокирует.
  2. (= R-03 из 12-review.md) Слой app.js (оркестратор, unit-aware ветка scale-bar) в репозитории покрыт только статикой. В этом прогоне пробел закрыт e2e: оркестратор проверен на живой масштабной линейке (TP-02/TP-04). Перерисовка карточек маршрута/связки через onUnitChange() инструментально не покрыта (нет OSRM); поведение подтверждено units.test.js на реальном коде + статикой test_app_js_*. Техдолг на DOM/MapLibre-харнесс для app.js остаётся.
  3. Окружение тестера. Пакеты shapely, mapbox-vector-tile (requirements.txt) и pytest-asyncio, ruff (pyproject.toml [dev]) не были предустановлены в песочнице — без shapely падал сбор test_health.py (импорт src.api.main). Тестер доустановил их по манифестам проекта. Это дефект провижининга окружения, не дефект ET-005. CI обязан выполнять pip install -r requirements.txt и .[dev] перед make test.

Замечания тестера

  • e2e-инструментарий. Playwright + Chromium установлены только в песочницу тестера для исполнения e2e. В артефакты проекта (requirements.txt, pyproject.toml, package.json) ничего не добавлено — ограничение 07-infra-requirements.md §6 («новые npm/Python пакеты — Нет», касается production/build-зависимостей) не нарушено. e2e-тесты 04-test-plan.yaml (TP-01…TP-05) явно ожидаются 07-infra-requirements.md §9; здесь они исполнены без изменения кода и тестов проекта. Скрипт прогона — временный, в репозиторий не коммитится.
  • Ручная сверка реализации: index.html:62-69 — сегментированный переключатель #unit-seg (кнопки unit-btn-km/unit-btn-mi) в попапе #terrain-popup после чекбокса POI, отделён <hr>; index.html:415units.js подключён строго перед app.js; app.js:2877-2948 — блок ET-005 (onUnitToggle, syncUnitToggleUI, оркестратор onUnitChange); app.js:2437-2438 — восстановление выбора и единственная подписка unitchange в DOMContentLoaded. Соответствует ТЗ, ADR-0001 и выводам 12-review.md.
  • Тесты не подгонялись под код; продакшн-код не правился; на prom ничего не запускалось.

Итог

Verdict: PASSstage:ready-to-deploy.

Весь тест-план (TP-01…TP-05) исполнен в реальном браузере и пройден; все 4 acceptance-критерия зелёные; pytest-регресс (31 passed) и lint чистые; JS-ошибок на странице нет; нефункциональное требование «пересчёт < 100 мс» выполнено с запасом (0,5 мс). Блокирующих (P0/P1) багов нет. Унаследованный из ревью T-01/P2 (сброс варианта связки) деплой не блокирует — решение по нему за dev. Готово к штатной перевыкладке фронтенда согласно 07-infra-requirements.md §7.