--- type: test-plan work_item_id: ET-007 title: "Test Plan: Спутниковая карта (Схема / Спутник)" version: 1 status: draft created_at: 2026-05-31 updated_at: 2026-05-31 authors: - "agent:analyst" test_suites: - name: unit-base-layer-state type: unit description: "Чтение/запись/восстановление выбора подложки" cases: - id: U-01 name: "Default — Схема, если localStorage пуст" input: "localStorage без ключа 'map-base-layer'" expected: "restoreBaseLayerState() выставляет base='schematic'" - id: U-02 name: "Чтение значения 'satellite' из localStorage" input: "localStorage['map-base-layer'] = 'satellite'" expected: "restoreBaseLayerState() выставляет base='satellite'" - id: U-03 name: "Запись значения при переключении" input: "onBaseLayerToggle('satellite')" expected: "localStorage['map-base-layer'] === 'satellite'" - id: U-04 name: "Игнор некорректного значения в localStorage" input: "localStorage['map-base-layer'] = 'unknown'" expected: "restoreBaseLayerState() fallback на 'schematic'" - id: U-05 name: "Toggle на уже активный режим — no-op" input: "active=schematic; onBaseLayerToggle('schematic')" expected: "Никаких изменений в стиле, localStorage не записывается повторно" - name: unit-ui-sync type: unit description: "Синхронизация .active у кнопок переключателя" cases: - id: U-10 name: "syncBaseLayerUI('satellite')" input: "DOM с #base-btn-schematic.active и #base-btn-satellite без класса" expected: "После: #base-btn-satellite.active=true, #base-btn-schematic.active=false" - id: U-11 name: "syncBaseLayerUI('schematic')" input: "DOM с #base-btn-satellite.active" expected: "После: #base-btn-schematic.active=true, #base-btn-satellite.active=false" - name: integration-maplibre-layers type: integration description: "Взаимодействие с MapLibre source/layer" cases: - id: I-01 name: "Добавление спутникового source при первом включении" input: "applyBaseLayer('satellite') впервые" expected: "map.getSource('satellite-raster') !== undefined; URL содержит arcgisonline.com" - id: I-02 name: "Добавление спутникового layer при первом включении" input: "applyBaseLayer('satellite') впервые" expected: "map.getLayer('satellite-base') !== undefined; type='raster'" - id: I-03 name: "Visibility OSM-base после переключения на спутник" input: "applyBaseLayer('satellite')" expected: "map.getLayoutProperty('osm-base', 'visibility') === 'none'" - id: I-04 name: "Visibility satellite-base после переключения на схему" input: "applyBaseLayer('satellite') → applyBaseLayer('schematic')" expected: "satellite-base.visibility==='none', osm-base.visibility==='visible'" - id: I-05 name: "Z-order: satellite ниже terrain и trails" input: "applyBaseLayer('satellite'); включены hillshade и trails" expected: "Layer index(satellite-base) < index(terrain-hillshade) < index(trails-track)" - id: I-06 name: "Position карты сохраняется при переключении" input: "center=[37.6,55.75], zoom=10; applyBaseLayer('satellite')" expected: "После: getCenter() == [37.6,55.75], getZoom() == 10" - id: I-07 name: "Атрибуция Esri зарегистрирована" input: "applyBaseLayer('satellite')" expected: "source 'satellite-raster' содержит attribution с упоминанием Esri" - name: integration-style-switch type: integration description: "Поведение при map.setStyle (смена темы)" cases: - id: I-10 name: "Спутник восстанавливается после setStyle (тёмная → светлая)" input: "active='satellite'; вызывается switchMapStyle()" expected: "После idle: layer 'satellite-base' существует; visibility='visible'; osm-base.visibility='none'" - id: I-11 name: "Сохранённое состояние читается из localStorage в rebuildMapOverlays" input: "localStorage='satellite'; rebuildMapOverlays() вручную" expected: "applyBaseLayer вызван с 'satellite'" - id: I-12 name: "Восстановление выполняется до restoreTerrainState" input: "rebuildMapOverlays() с заглушками-shpions" expected: "Порядок вызовов: restoreBaseLayerState → restoreTerrainState" - name: integration-other-layers type: integration description: "Совместимость со всеми клиентскими слоями" cases: - id: I-20 name: "Маршрут OSRM не теряется при переключении" input: "Построен маршрут; applyBaseLayer('satellite')" expected: "Layer маршрута существует, координаты не изменились" - id: I-21 name: "GPX-трек не теряется при переключении" input: "Загружен GPX; applyBaseLayer('satellite')" expected: "Layer gpx-* существует, source.data не изменён" - id: I-22 name: "Recon-круг не теряется при переключении" input: "Активен recon; applyBaseLayer('satellite')" expected: "Recon-круг отображается на карте" - id: I-23 name: "Hillshade поверх спутника" input: "applyBaseLayer('satellite'); включить hillshade" expected: "Оба слоя видимы; hillshade выше satellite-base в стиле" - id: I-24 name: "POI halo чёрный на спутнике" input: "applyBaseLayer('satellite')" expected: "map.getPaintProperty('poi-labels','text-halo-color') === '#000000' (или эквивалент)" - id: I-25 name: "POI halo дефолтный на схеме" input: "applyBaseLayer('schematic') после спутника" expected: "POI labels вернули halo цвет схемы (#ffffff)" - name: e2e-base-layer-workflow type: e2e description: "Полный пользовательский сценарий" cases: - id: E-01 name: "Открыть попап → включить спутник → сохранилось" steps: - "Открыть приложение (default — Схема)" - "Нажать кнопку «Рельеф» в правой панели" - "Убедиться: переключатель «Подложка» виден" - "Нажать «Спутник»" - "Убедиться: спутниковые тайлы загрузились" - "Убедиться: атрибуция Esri видна" - "Перезагрузить страницу" - "Убедиться: после загрузки активен «Спутник»" - id: E-02 name: "Переключение туда-обратно без потери маршрута" steps: - "Построить маршрут через OSRM (2 точки)" - "Переключить на «Спутник»" - "Убедиться: маршрут виден на спутнике, статистика сохранена" - "Переключить на «Схема»" - "Убедиться: маршрут виден на схеме, статистика та же" - id: E-03 name: "Спутник + загрузка GPX" steps: - "Переключить на «Спутник»" - "Загрузить GPX-файл" - "Убедиться: трек отрисован поверх спутника" - "Убедиться: цвет трека различим" - id: E-04 name: "Спутник + смена темы" steps: - "Переключить на «Спутник»" - "Переключить тёмную тему на светлую" - "Дождаться idle" - "Убедиться: подложка осталась «Спутник»" - "Убедиться: все остальные слои восстановились" - id: E-05 name: "Спутник + переключение единиц измерения" steps: - "Переключить на «Спутник»" - "Открыть попап слоёв и переключить «мили»" - "Убедиться: единицы переключились, подложка не сбросилась" - id: E-06 name: "Спутник + hillshade" steps: - "Переключить на «Спутник»" - "Включить «Тени рельефа»" - "Убедиться: видны спутник и тени одновременно" - id: E-07 name: "Линейка на спутнике" steps: - "Переключить на «Спутник»" - "Активировать линейку" - "Поставить 3 точки на карте" - "Убедиться: линия линейки видна на спутнике" - "Убедиться: расстояния отображаются" - name: e2e-error-handling type: e2e description: "Поведение при сетевых ошибках" cases: - id: E-10 name: "Спутниковые тайлы недоступны (offline)" steps: - "Включить «Спутник»" - "Симулировать offline (DevTools throttling: Offline)" - "Сдвинуть карту в новую область" - "Убедиться: приложение не падает; видим фон background" - "Восстановить сеть → тайлы догружаются" test_data: - name: "test-track-simple.gpx" description: "1 трек, 10 точек — для проверки совместимости с GPX" - name: "Тестовый OSRM-маршрут" description: "2 waypoint в районе [37.6,55.75] → [37.7,55.8]"