Files
enduro-trails/docs/work-items/ET-013/04-test-plan.yaml
claude-bot 7df1ffe75c
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 9s
CI / build (push) Successful in 2s
analyst(ET): auto-commit from analyst run_id=78
2026-06-04 09:28:51 +00:00

337 lines
15 KiB
YAML
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.
---
type: test-plan
work_item_id: ET-013
title: "Test Plan: Перепады высот на z9-z11"
version: 1
status: draft
created_at: 2026-06-04
updated_at: 2026-06-04
authors:
- "agent:analyst"
related:
- "PH-6.terrain"
- "ET-007"
scope_note: >
ET-013 — frontend-калибровка: понижает UI-минзум hillshade с 10 до 9
и переводит paint-параметры (raster-opacity, raster-contrast,
raster-resampling) hillshade и TRI в zoom-aware форму. Backend
и pipeline растровых тайлов не трогаются. Тест-план фокусируется
на:
(1) корректности новых zoom-tier paint-выражений;
(2) обратной совместимости applyTerrainLayer;
(3) визуальной читаемости перепадов на z9-z11;
(4) регрессии z8 (TRI не изменился), z14 (hillshade не перегрет);
(5) совместимости с тёмной темой и спутниковой подложкой;
(6) что network-объём не уплыл больше +35%.
test_suites:
- name: unit-terrain-paint
type: unit
description: "Структура paint-выражений HILLSHADE_PAINT и TRI_PAINT"
cases:
- id: UT-PAINT-HS-OPACITY
name: "HILLSHADE_PAINT: raster-opacity — interpolate с правильными stops"
input: |
Python-парсер: чтение src/web/app.js, regex по блоку
HILLSHADE_PAINT = { ... }; вытаскивание raster-opacity.
expected: |
Тип: ['interpolate', ['linear'], ['zoom'], ...].
Stops содержат: (9, 0.65), (10, 0.60), (11, 0.55),
(12, 0.50), (14, 0.40). Допустимо отклонение значений ±0.05
(калибровка) — но порядок монотонно убывающий от 9 к 14.
- id: UT-PAINT-HS-CONTRAST
name: "HILLSHADE_PAINT: raster-contrast — пик на z9, 0 на z14"
input: |
Тот же парсер.
expected: |
Тип interpolate. Значение на z=9 ≥ 0.30. Значение на z=14
≤ 0.10. Монотонно убывает.
- id: UT-PAINT-HS-RESAMPLING
name: "HILLSHADE_PAINT: raster-resampling = 'nearest'"
input: |
Парсер.
expected: |
Строка 'nearest' (не 'linear').
- id: UT-PAINT-TRI-OPACITY-Z8
name: "TRI_PAINT: на z8 opacity = 0.70 (регрессия)"
input: |
Парсер по TRI_PAINT.
expected: |
Stop (8, 0.70) присутствует ровно (без округления).
- id: UT-PAINT-TRI-OPACITY-PEAK
name: "TRI_PAINT: пик на z9-z11"
input: |
Парсер.
expected: |
Stops содержат (10, X) с X ≥ 0.80 и (11, Y) с Y ≥ 0.80.
- id: UT-PAINT-TRI-RESAMPLING
name: "TRI_PAINT: raster-resampling = 'nearest'"
input: |
Парсер.
expected: |
'nearest'.
- id: UT-PAINT-COMPAT-01
name: "applyTerrainLayer обратно-совместим с числовым opacity"
input: |
Вызов с opacity=0.5 (Node + JSDOM-mock карты).
expected: |
Внутри map.addLayer передан paint:
{ 'raster-opacity': 0.5, 'raster-resampling': 'linear' }.
notes: |
Если запуск JS-теста не настроен — заменить на статический
grep по src/web/app.js: проверить ветвление
'typeof opacityOrPaint === "number"'.
- id: UT-PAINT-COMPAT-02
name: "applyTerrainLayer принимает paint-объект"
input: |
Вызов с opacityOrPaint = { 'raster-opacity': 0.4,
'raster-contrast': 0.2, 'raster-resampling': 'nearest' }.
expected: |
Этот объект передан в map.addLayer paint как есть.
- id: UT-REG-MINZOOM-9
name: "updateHillshadeAvailability порог = 9"
input: |
grep по src/web/app.js: 'if (zoom < 9)' внутри функции
updateHillshadeAvailability.
expected: |
Совпадение найдено; 'if (zoom < 10)' отсутствует.
- id: UT-REG-HINT-TEXT
name: "Hint текст обновлён до 'Зум 9+'"
input: |
grep по src/web/index.html: '#terrain-hillshade-hint'
содержит 'Зум 9+'.
expected: |
Совпадение найдено; 'Зум 10+' отсутствует.
- id: UT-REG-CALLERS
name: "applyTerrainLayer вызывается ровно дважды в onTerrainCheckbox"
input: |
regex 'applyTerrainLayer\s*\(' в src/web/*.js — count.
expected: |
Минимум 2 вызова в src/web/app.js. Все они находятся
внутри функции onTerrainCheckbox.
- name: integration-terrain-tiles
type: integration
description: "Endpoint /terrain/{layer}/{z}/{x}/{y}.png на z9-z11"
cases:
- id: IT-TILE-Z9-01
name: "Тайл z=9 для hillshade: 200 или skipped если данных нет"
input: |
Test-среда или CI с TERRAIN_DIR. Найти первый существующий
тайл z9 в директории hillshade, выполнить GET.
expected: |
Если data/terrain/hillshade/9/ существует:
status 200, content-type image/png, тело > 0.
Иначе:
test skipped с reason 'PH-6 data not in repo'.
- id: IT-TILE-Z10-01
name: "Тайл z=10 для hillshade: 200 или skipped"
input: |
То же, что IT-TILE-Z9-01 для z=10.
expected: |
status 200 или skipped.
- id: IT-TILE-Z11-01
name: "Тайл z=11 для hillshade: 200 или skipped"
input: |
То же для z=11.
expected: |
status 200 или skipped.
- id: IT-TILE-TRI-Z9
name: "TRI на z9 доступен (минзум 5, тайлы должны быть)"
input: |
GET tiles/9/X/Y.png под TRI.
expected: |
200 или skipped (если данных нет на CI).
- id: IT-TILE-INVALID-LAYER
name: "Неизвестный layer → 404 (регрессия)"
input: |
GET /terrain/unknown/9/0/0.png
expected: |
status 404.
- id: IT-TILE-MISSING
name: "Несуществующий тайл → 404 (регрессия)"
input: |
GET /terrain/hillshade/9/99999/99999.png
expected: |
status 404.
- id: IT-TILE-CACHE-HEADER
name: "Cache-Control: immutable сохраняется"
input: |
GET существующего тайла.
expected: |
Header 'Cache-Control' содержит 'immutable' и max-age=31536000.
- name: regression-existing
type: regression
description: "Регрессия ET-007 / PH-6 / общих unit-тестов"
cases:
- id: RG-UNIT-ALL
name: "Все unit-тесты проекта зелёные"
input: "pytest tests/unit/ -v"
expected: "exit-code 0"
- id: RG-INTEG-ALL
name: "Все integration-тесты проекта зелёные"
input: "pytest tests/integration/ -v"
expected: "exit-code 0"
- id: RG-LINT
name: "Линтеры зелёные"
input: "make lint"
expected: "exit-code 0"
- name: ui-playwright
type: ui
description: "Playwright UI-тесты на test-среде"
reference: "04b-ui-test-cases.md"
cases:
- id: UI-LINK-01
name: "См. 04b-ui-test-cases.md — TC-UI-01..TC-UI-12"
expected: |
Каждый TC выполняется; check-visual подтверждается
оператором либо визуальным diff-инструментом
(baseline до ET-013 vs текущий).
- name: manual-deploy-validation
type: e2e
description: "Ручная проверка в test-среде после деплоя"
marker: "manual"
cases:
- id: E2E-PRE-DEPLOY-01
name: "Pre-deploy: тайлы z9-z11 на test-среде доступны"
steps:
- "curl -sI https://openclaw.mva154.duckdns.org/enduro/terrain/hillshade/9/308/158.png | head -1"
- "curl -sI https://openclaw.mva154.duckdns.org/enduro/terrain/hillshade/10/617/317.png | head -1"
- "curl -sI https://openclaw.mva154.duckdns.org/enduro/terrain/hillshade/11/1234/635.png | head -1"
- "Все три — HTTP/1.1 200 OK. При 404 — стоп, открыть PH-6 follow-up."
- "Зафиксировать в 14-deploy-log.md."
- id: E2E-DEPLOY-01
name: "Hillshade доступен на z=9"
steps:
- "Открыть https://openclaw.mva154.duckdns.org/enduro/"
- "localStorage.clear(); location.reload()"
- "Click #terrain-toggle"
- "В Console: window._map.setZoom(9); window._map.setCenter([37.6, 54.5])"
- "Wait 2s"
- "Кнопка #terrain-hillshade-cb имеет disabled=false"
- "Hint #terrain-hillshade-hint имеет display:none"
- "Click #terrain-hillshade-cb"
- "Wait 3s"
- "На карте видны тени"
- "Screenshot et013-deploy-z9.png"
- "Зафиксировать в 14-deploy-log.md"
- id: E2E-DEPLOY-02
name: "Network-объём: рост ≤ 35%"
steps:
- "Открыть DevTools Network, фильтр /terrain/"
- "Очистить network log"
- "В Console: window._map.setZoom(8); ждать 3s; setZoom(9); ждать 3s; setZoom(10); ждать 3s; setZoom(11); ждать 3s"
- "Замерить суммарный transferred size в фильтре /terrain/"
- "Сравнить с baseline (записан в 13-test-report.md до ET-013): рост ≤ 135%"
- "Зафиксировать"
- id: E2E-DEPLOY-03
name: "Регрессия z=8 (TRI выглядит как до ET-013)"
steps:
- "localStorage.clear(); location.reload()"
- "Включить только #terrain-tri-cb (без hillshade)"
- "window._map.setZoom(8); setCenter([37.6, 54.5])"
- "Screenshot et013-deploy-z8-tri-regress.png"
- "Визуально сравнить с baseline из 13-test-report.md до ET-013 — не отличается заметно."
- id: E2E-DEPLOY-04
name: "Регрессия z=14 (hillshade не перегрет)"
steps:
- "Включить #terrain-hillshade-cb"
- "window._map.setZoom(14); setCenter([37.6, 54.5])"
- "Screenshot et013-deploy-z14-regress.png"
- "Эффективное raster-opacity ≈ 0.40, raster-contrast ≈ 0"
- "В Console: window._map.getPaintProperty('terrain-hillshade', 'raster-opacity')"
- "(вернёт interpolate-выражение — proof zoom-aware)"
- id: E2E-DEPLOY-05
name: "Спутник + hillshade на z=10 (R-3)"
steps:
- "Включить hillshade, переключить #base-btn-satellite"
- "window._map.setZoom(10); setCenter([37.6, 54.5])"
- "Screenshot et013-deploy-z10-sat.png"
- "Визуальная приёмка: hillshade видим, не глушит снимок"
- "При проблеме — задача отправляется на корректировку stops"
- id: E2E-DEPLOY-06
name: "Тёмная тема + hillshade на z=10 (R-2)"
steps:
- "Click #btn-theme (переключить в тёмную)"
- "window._map.setZoom(10)"
- "Screenshot et013-deploy-z10-dark.png"
- "Визуальная приёмка: hillshade читается, не сливается с тёмной подложкой"
- id: E2E-DEPLOY-07
name: "Persistence: F5 не теряет состояние"
steps:
- "Включить оба чекбокса"
- "location.reload()"
- "Чекбоксы остаются включёнными"
- "На текущем zoom оба слоя восстановлены"
test_data:
fixtures_dir: "tests/fixtures/terrain/"
fixtures:
- name: "hillshade-z9-sample.png"
description: |
Опционально: один валидный PNG-тайл из data/terrain/hillshade/9/
для CI-окружения без полного набора данных. Скопировать любой
тайл над ЦФО, переименовать. ~10 KB.
- name: "hillshade-z10-sample.png"
description: "То же для z10."
- name: "tri-z10-sample.png"
description: "TRI sample для z10."
notes:
- "Если на CI нет TERRAIN_DIR с данными — IT-TILE-* тесты skipped (REQ-F-15)."
- "Сравнения 'до/после' визуальные — baseline скриншоты лежат в 13-test-report.md и фиксируются до начала ET-013."
- "Для unit-тестов paint никаких fixture не нужно — парсинг исходника."
test_environment:
unit:
- "Python 3.12, pytest"
- "regex-парсер src/web/app.js (Вариант B в TRZ REQ-F-13)"
- "Опционально Node + JSDOM, если в проекте появятся JS-тесты"
integration:
- "FastAPI TestClient против src.api.main:app"
- "TERRAIN_DIR через env или skip-if-missing"
performance:
- "Не требуется специально: NFR-01/02 говорят о невидимом изменении render-time"
- "Сетевой объём — ручной замер в DevTools Network (E2E-DEPLOY-02)"
e2e:
- "Test-среда https://openclaw.mva154.duckdns.org/enduro/"
- "Playwright (см. 04b-ui-test-cases.md)"
ci_gates:
- "Unit UT-PAINT-* и UT-REG-* — обязательны (AC-15)"
- "Integration IT-TILE-* — обязательны (с skipif для отсутствующих данных) (AC-16)"
- "Регрессия RG-UNIT-ALL, RG-INTEG-ALL, RG-LINT — обязательны (AC-17, AC-18)"
- "Pre-deploy E2E-PRE-DEPLOY-01 — ручной gate перед merge (AC-19)"
- "UI-тесты Playwright — после деплоя, фиксация в 13-test-report.md"
- "E2E-DEPLOY-01..07 — ручные шаги в 14-deploy-log.md"
---