Integration тесты

Интеграционное тестирование в контексте Mapbox GL JS связано с проверкой взаимодействия между кодом приложения, библиотекой рендеринга карт, источниками данных и пользовательскими слоями. В отличие от модульных тестов, здесь проверяется не отдельная функция, а поведение системы в целом: корректность инициализации карты, загрузка стиля, добавление источников данных, отображение слоёв, реакция на события и синхронизация состояния.

Mapbox GL JS опирается на WebGL, DOM-события и асинхронную загрузку ресурсов, что делает интеграционные тесты сложнее традиционных frontend-сценариев. Основная сложность заключается в том, что тестовая среда должна воспроизводить браузерное окружение, поддерживать canvas и частично имитировать WebGL.


Ограничения тестовой среды и стратегия абстракции

Node.js в связке с jsdom не предоставляет полноценного WebGL-контекста. Это накладывает ограничение на прямое тестирование рендеринга карты. Поэтому интеграционные тесты Mapbox GL JS обычно строятся вокруг следующих уровней абстракции:

  • проверка состояния карты (style, sources, layers)
  • проверка вызовов API Mapbox GL JS
  • проверка событий жизненного цикла карты
  • частичная визуальная проверка через headless Chromium
  • мокирование WebGL и сетевых запросов

Ключевая стратегия заключается в том, чтобы отделить «рендеринг пикселей» от «логики конфигурации карты».


Подготовка тестового окружения

Для интеграционных тестов применяются различные инструменты:

  • Jest или Vitest для тест-раннера
  • Playwright или Cypress для end-to-end и интеграционных сценариев
  • MSW (Mock Service Worker) для перехвата сетевых запросов
  • jest-canvas-mock или headless-gl для имитации Canvas/WebGL

Особое внимание уделяется стабильности окружения. Mapbox GL JS активно использует асинхронные загрузки стилей и тайлов, поэтому тесты должны учитывать задержки и события готовности карты.


Инициализация карты в тестах

Типичный сценарий интеграционного теста начинается с создания контейнера и инициализации карты:

  • создаётся DOM-элемент
  • инициализируется Mapbox GL JS объект
  • ожидается событие загрузки стиля

Критическим моментом является событие load, которое сигнализирует о завершении загрузки стиля и готовности карты к модификации.

В тестовой среде важно синхронизировать выполнение через промисы или event listeners, иначе возможны гонки состояний.


Проверка добавления источников и слоёв

Одним из ключевых интеграционных сценариев является проверка корректного добавления источников данных и слоёв:

  • map.addSource() должен корректно регистрировать источник
  • map.addLayer() должен добавлять слой в правильный порядок
  • зависимости между слоями должны соблюдаться

Проверка обычно выполняется через:

  • map.getSource(id)
  • map.getLayer(id)
  • map.getStyle().layers

Интеграционные тесты здесь не проверяют визуальный результат, а подтверждают консистентность внутреннего состояния style-объекта.


Работа с событиями карты

Mapbox GL JS предоставляет богатую систему событий:

  • load
  • idle
  • render
  • move
  • zoom

Интеграционные тесты часто фокусируются на корректности последовательности событий.

Особенно важны сценарии:

  • карта полностью загружена до модификации
  • события движения карты корректно вызываются при программном изменении центра
  • обработчики не вызываются дублирующе при повторной инициализации

Для стабилизации тестов применяется ожидание событий через промисы-обёртки.


Мокирование сетевых запросов

Mapbox GL JS активно загружает внешние ресурсы:

  • стили (style JSON)
  • тайлы (vector/raster tiles)
  • sprite и glyphs

В интеграционных тестах эти запросы обычно перехватываются:

  • MSW для HTTP-уровня
  • кастомные fetch-mock реализации
  • локальные фикстуры JSON

Структура теста часто зависит от детерминированного style JSON, который исключает нестабильность, связанную с внешними API.


Проверка кастомных слоёв и источников

Интеграционные тесты часто включают кастомную логику:

  • GeoJSON источники
  • heatmap слои
  • custom WebGL layers
  • clustering

Проверка строится на последовательности:

  • добавление source
  • добавление layer
  • обновление данных через setData
  • проверка обновления состояния через queryRenderedFeatures

Особое внимание уделяется корректности обновления данных без полной переинициализации карты.


Тестирование взаимодействия пользователя

Интеграционные сценарии часто моделируют пользовательские действия:

  • zoom in / zoom out
  • pan (drag)
  • click on feature
  • hover interactions

В Playwright или Cypress такие сценарии реализуются через симуляцию событий мыши и клавиатуры.

Ключевая проверка заключается не в визуальном результате, а в реакции приложения:

  • открытие popup
  • изменение состояния UI
  • обновление фильтров источников

Headless-рендеринг и визуальная валидация

Полноценная визуальная проверка Mapbox GL JS возможна только в headless Chromium или реальном браузере.

Используются подходы:

  • snapshot-тестирование canvas
  • сравнение скриншотов (pixel diff)
  • контроль стабильных состояний карты (fixed viewport)

Проблема нестабильности WebGL рендеринга требует:

  • фиксации размера контейнера
  • отключения анимаций
  • использования фиксированных тайлов и стилей

Тестирование кастомных контролов

Mapbox GL JS поддерживает пользовательские controls через интерфейс IControl.

Интеграционные тесты проверяют:

  • добавление control через map.addControl()
  • корректное появление DOM-элементов
  • обработку событий click/change
  • удаление через map.removeControl()

Особое значение имеет корректное управление жизненным циклом DOM-узлов, чтобы избежать утечек памяти при повторной инициализации карты.


Проверка синхронизации состояния приложения

В приложениях Mapbox GL JS часто используется внешнее состояние (Redux, Zustand, MobX).

Интеграционные тесты проверяют:

  • синхронизацию фильтров с источниками данных
  • реакцию карты на изменение глобального состояния
  • отсутствие циклических обновлений между картой и store

Критический аспект — контроль побочных эффектов при изменении карты, чтобы исключить бесконечные циклы обновлений.


Детализация ошибок и диагностика

Интеграционные тесты Mapbox GL JS требуют расширенного логирования:

  • события карты
  • изменения style
  • ошибки загрузки ресурсов
  • WebGL предупреждения

Часто добавляются утилиты, которые подписываются на:

  • map.on('error')
  • map.on('data')
  • map.on('styledata')

Это позволяет локализовать проблемы, связанные с несовместимостью стилей или источников.


Паттерны стабильных тестов

Для повышения надёжности интеграционных тестов используются следующие подходы:

  • фиксация версии Mapbox GL JS
  • использование локальных style JSON
  • отключение сетевых задержек
  • синхронное ожидание событий карты
  • изоляция каждого теста через пересоздание контейнера

Дополнительно применяется стратегия минимизации асинхронности через явные await на события карты.


Тестирование производных компонентов

В реальных приложениях Mapbox GL JS часто оборачивается в абстракции:

  • MapService
  • MapManager
  • React/Vue компоненты

Интеграционные тесты в этом случае проверяют:

  • корректную инициализацию обёртки
  • проброс конфигурации в Mapbox GL JS
  • реакцию на изменения props/state
  • корректное уничтожение карты при unmount

Особое внимание уделяется корректному вызову map.remove() для освобождения ресурсов WebGL.


Стратегии изоляции и повторяемости

Повторяемость интеграционных тестов достигается за счёт:

  • одинакового начального состояния карты
  • фиксированных координат и zoom
  • детерминированных GeoJSON данных
  • отключения анимаций и easing функций

Без этих условий тесты становятся нестабильными из-за особенностей WebGL и асинхронного рендеринга.


Обработка нестабильных сценариев

Mapbox GL JS может проявлять недетерминированность в следующих случаях:

  • параллельная загрузка тайлов
  • различия в производительности CI окружений
  • race conditions при добавлении слоёв

Для стабилизации применяются:

  • retry-логика ожидания состояния карты
  • проверка через polling состояния style
  • увеличение таймаутов в CI

Интеграция с CI/CD

В CI окружениях интеграционные тесты Mapbox GL JS требуют:

  • headless Chromium (Playwright)
  • выделенного GPU или software rendering
  • ограничения параллельного выполнения тестов

Типичная проблема CI — отсутствие WebGL, решается через:

  • --use-gl=swiftshader
  • fallback на software renderer
  • контейнеризацию с поддержкой GPU abstraction

Архитектурные подходы к тестируемому коду

Код, использующий Mapbox GL JS, становится тестируемым при соблюдении следующих принципов:

  • инкапсуляция инициализации карты
  • отсутствие прямых side-effect вызовов вне контролируемых функций
  • явное управление жизненным циклом карты
  • отделение данных от визуализации

Такая архитектура упрощает интеграционные тесты и снижает количество моков.


Комбинация интеграционных и e2e сценариев

Интеграционные тесты Mapbox GL JS часто комбинируются с end-to-end тестированием:

  • интеграционные тесты проверяют состояние карты
  • e2e тесты проверяют пользовательский поток

Граница между ними проходит по уровню абстракции:

  • интеграционные: API карты и состояние style
  • e2e: поведение интерфейса и пользовательские сценарии