--- type: test-report work_item_id: ET-002 version: 1 status: pass tester: "agent:tester" date: 2026-05-21 commit_tested: 8c17a4f verdict: PASS --- # Test Report — ET-002 ## Verdict: **PASS** → `stage:ready-to-deploy` Полный регресс зелёный: **14 passed, 4 skipped, 0 failed**, lint чистый, JS-юнит-тесты POI 7/7 pass, тест-окружение отвечает 200. Блокирующих багов (P0/P1) не найдено. Тест-кейсы TP-01..TP-04 и TP-08 из `04-test-plan.yaml` исполнены и прошли. e2e-кейсы TP-05..TP-07, TP-09 **не исполнялись** — в репозитории нет Playwright-инфраструктуры, а `07-infra-requirements.md §6` запрещает новые npm-пакеты (конфликт двух approved-артефактов, зафиксирован reviewer'ом как R-01/P2). Поведенческая суть этих сценариев покрыта unit- и статическими тестами. На merge/деплой ET-002 не влияет. ## Окружение - **Дата прогона:** 2026-05-21 - **Ветка:** `feature/ET-002-poi-toggle` - **Коммит:** `8c17a4f` (`feat(web): add POI visibility checkbox to terrain popup`; взят из `12-review.md` — `git` в окружении тестера недоступен) - **Python:** 3.12.13 - **pytest:** 8.3.3 (plugins: asyncio-1.3.0, anyio-4.13.0) - **Node:** v22.22.2 (`node --test`) - **ruff:** 0.15.14 - **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 | | test API | https://openclaw.mva154.duckdns.org/enduro/api/health | 200 `{"status":"ok","db_exists":true}` | ET-002 — фронтенд-изменение; в test задеплоен `main`, поэтому healthcheck подтверждает только живость окружения, а не наличие фичи (фича попадёт в test штатной перевыкладкой после merge). ## Команды запуска ```bash # Unit + integration (эквивалент make test) python -m pytest tests/ -v # JS behavioral unit-тесты POI (TP-01..TP-04) node --test tests/unit/poi_toggle.test.js # Lint ruff check src/ ruff check tests/ ``` ## Результаты pytest `python -m pytest tests/ -v` → **14 passed, 4 skipped, 1 warning in 0.51s** | # | Тест | Тип | Результат | |---|---|---|---| | 1 | `test_routing_barriers.py::test_lua_syntax` | unit (структура lua) | **PASS** | | 2 | `test_routing_barriers.py::test_blocked_barriers_match_trz` | static AC | **PASS** | | 3 | `test_routing_barriers.py::test_excluded_highways_match_trz` | static AC | **PASS** | | 4 | `test_routing_barriers.py::test_route_avoids_barrier` | integration | **SKIP** (OSRM недоступен) | | 5 | `test_routing_barriers.py::test_route_no_footway` | integration | **SKIP** (OSRM недоступен) | | 6 | `test_routing_barriers.py::test_route_allows_cattle_grid` | integration | **SKIP** (OSRM недоступен) | | 7 | `test_routing_barriers.py::test_existing_route_works` | regression | **SKIP** (OSRM недоступен) | | 8 | `test_health.py::test_health_endpoint` | unit (async) | **PASS** | | 9 | `test_poi_toggle.py::test_poi_checkbox_present_in_html` | static (REQ-F-01) | **PASS** | | 10 | `test_poi_toggle.py::test_poi_checkbox_checked_by_default` | static (REQ-F-02) | **PASS** | | 11 | `test_poi_toggle.py::test_poi_checkbox_placed_after_trails_separated_by_hr` | static (REQ-F-01) | **PASS** | | 12 | `test_poi_toggle.py::test_poi_checkbox_uses_shared_style_class` | static (UI-спец) | **PASS** | | 13 | `test_poi_toggle.py::test_poi_functions_defined` | static (ADR-0001) | **PASS** | | 14 | `test_poi_toggle.py::test_poi_logic_uses_localstorage_key` | static (REQ-F-05) | **PASS** | | 15 | `test_poi_toggle.py::test_poi_logic_reuses_layer_state_and_groups` | static (ADR п.3-4) | **PASS** | | 16 | `test_poi_toggle.py::test_restore_poi_state_wired_into_init` | static (REQ-F-06) | **PASS** | | 17 | `test_poi_toggle.py::test_poi_visibility_toggled_via_set_layout_property` | static (ADR п.1) | **PASS** | | 18 | `test_poi_toggle.py::test_js_unit_tests_pass` | behavioral (Node-раннер) | **PASS** | **4 SKIP** — интеграционные тесты роутинга ET-001; требуют поднятого OSRM (`OSRM_URL`, по умолчанию `http://172.22.0.1:5559`), который в окружении тестера недоступен. Это штатное поведение (`test_routing_barriers.py` помечает их `skip`, чтобы CI без инфраструктуры не падал). ET-002 — фронтенд-изменение, на роутинг влиять не может; к регрессу не относится. Предупреждение `PendingDeprecationWarning` из `starlette/formparsers.py` — внешняя зависимость, к ET-002 отношения не имеет, не блокирует. ## Результаты JS unit-тестов (TP-01..TP-04) `node --test tests/unit/poi_toggle.test.js` → **# pass 7, # fail 0** Тесты исполняют **реальный** код POI-блока из `src/web/app.js` (блок извлекается по маркерам `ET-002 POI visibility block` и оборачивается через `new Function` с инъекцией моков). | Тест | TC | Результат | |---|---|---| | снятый чекбокс скрывает слои POI и сохраняет `0` | TP-01 | **PASS** | | установленный чекбокс показывает слои POI и сохраняет `1` | TP-02 | **PASS** | | `restorePoiState()` при `poi-visible=0` скрывает POI | TP-03 | **PASS** | | `restorePoiState()` без ключа включает POI по умолчанию | TP-04 | **PASS** | | `restorePoiState()` при `poi-visible=1` показывает POI | доп. | **PASS** | | `onPoiCheckbox()` меняет только `poi-circles`/`poi-labels` | доп. (дух TP-08) | **PASS** | | `applyPoiVisibility()` синхронизирует `layerState` без слоёв | доп. | **PASS** | ## Результаты lint | Команда | Результат | |---|---| | `ruff check src/` | **All checks passed!** | | `ruff check tests/` | **All checks passed!** | ## Покрытие тест-плана (04-test-plan.yaml) | TC | Тип | Исполнение | Статус | |---|---|---|---| | **TP-01** | unit | JS-тест «TP-01» (через `test_js_unit_tests_pass`) | **PASS** | | **TP-02** | unit | JS-тест «TP-02» | **PASS** | | **TP-03** | unit | JS-тест «TP-03» | **PASS** | | **TP-04** | unit | JS-тест «TP-04» | **PASS** | | **TP-05** | e2e | **BLOCKED** (нет Playwright). Покрыто статически: `test_poi_checkbox_present_in_html`, `test_poi_checkbox_placed_after_trails_separated_by_hr` | COVERED (alt) | | **TP-06** | e2e | **BLOCKED** (нет Playwright). Покрыто поведенчески: JS «TP-01»/«TP-02», «меняет только poi-circles/poi-labels» | COVERED (alt) | | **TP-07** | e2e | **BLOCKED** (нет Playwright). Покрыто поведенчески: JS «TP-03» (`restorePoiState` при `poi-visible=0`) | COVERED (alt) | | **TP-08** | integration | JS «onPoiCheckbox() меняет только слои poi-circles и poi-labels» — изоляция чужих слоёв подтверждена | **PASS** (alt) | | **TP-09** | e2e | **BLOCKED** (нет Playwright). Класс `terrain-checkbox` подтверждён статически; по touch-target см. P3-2 | PARTIAL | **Исполнено и пройдено: TP-01..TP-04, TP-08 (5/9).** **e2e TP-05..TP-07, TP-09 (4/9) — заблокированы инфраструктурой**, их поведение покрыто unit/статикой. Прямой инструментальной проверки в реальном браузере не было. ## Соответствие Acceptance Criteria | AC | Описание | Источник проверки | Статус | |---|---|---|---| | AC-01 | Чекбокс в попапе после «Тропы», отделён `
` | `test_poi_checkbox_placed_after_trails_separated_by_hr` | **PASS** | | AC-02 | POI включены по умолчанию | `test_poi_checkbox_checked_by_default` + JS «TP-04» | **PASS** | | AC-03 | Скрытие POI → `visibility: none` | JS «TP-01» | **PASS** | | AC-04 | Показ POI → `visibility: visible` | JS «TP-02» | **PASS** | | AC-05 | Состояние сохраняется после перезагрузки | JS «TP-03» (`restorePoiState` при `poi-visible=0`) | **PASS** | | AC-06 | Восстановление включённого состояния | JS «restorePoiState при poi-visible=1» | **PASS** | | AC-07 | Не ломает существующие чекбоксы | JS «меняет только poi-circles/poi-labels»; HTML-изменения аддитивны | **PASS** | | AC-08 | Синхронизация с `layerState.poi` | JS «TP-01»/«TP-02» + «applyPoiVisibility без слоёв» | **PASS** | Все 8 критериев имеют поведенческое покрытие; ни один не нарушен. Браузерная (e2e) проверка AC-01/03/04/05 ограничена отсутствием Playwright — поведение подтверждено на уровне реального кода POI-блока. ## Найденные баги ### P0 (блокирующие) Нет. ### P1 (критические) Нет. ### P2 (важные) **T-01 (= R-01 из `12-review.md`) — e2e TP-05..TP-09 не исполнимы.** `04-test-plan.yaml` определяет TP-05..TP-09 как `type: e2e`, но `07-infra-requirements.md §6` запрещает новые npm-пакеты, а Playwright-инфраструктуры в репозитории нет (проверено: нет `package.json`, `node_modules`, бинаря `playwright`, `npx`). Это конфликт двух **approved**-артефактов, а не дефект разработки. Поведение покрыто unit/статикой. **Действие:** Analyst — согласовать `04-test-plan.yaml` с `07-infra-requirements.md` (пометить TP-05..09 как покрытые альтернативно либо завести инфра-задачу на Playwright). **Merge/деплой ET-002 не блокирует.** ### P3 (косметика / наблюдения) 1. **(= R-02 из `12-review.md`)** `app.js:2849` — `const poiOn = stored === null || stored === '1';`: нештатное значение ключа `poi-visible` трактуется как «скрыть». Надёжнее `stored !== '0'` (деградация к дефолту «показать», REQ-F-02). Крайний кейс — ключ пишет только это приложение. Не блокирует. 2. **REQ-NF-03 (touch target ≥ 44px)** — `.terrain-checkbox` (`app.css:806`) при `padding:8px` и `font-size:15px` даёт высоту строки ≈ 35px, что ниже ориентира 44px. Однако чекбокс POI использует **тот же** класс, что и все соседние чекбоксы попапа (Тени/Перепады/Грунтовки/Тропы) — **регрессии нет**, кликабельна вся строка-`