E2E тесты

Особенности E2E тестирования WebGL-карт

End-to-End (E2E) тестирование веб-приложений с картографическими компонентами принципиально отличается от тестирования классических DOM-интерфейсов. В случае приложений, использующих Mapbox GL JS, ключевая сложность заключается в том, что визуализация рендерится через WebGL, а не через стандартные HTML-элементы.

Это приводит к нескольким особенностям:

  • результат теста часто является визуальным, а не структурным;
  • состояние карты зависит от асинхронной загрузки тайлов и стилей;
  • отрисовка происходит на canvas, который не содержит DOM-узлов;
  • поведение карты зависит от GPU и окружения выполнения тестов.

E2E тесты в таких системах ориентируются не только на DOM-события, но и на состояние рендера, сетевые запросы и визуальный результат кадра.


Событийная модель загрузки карты

В Mapbox GL JS критическим моментом является завершение загрузки стиля и тайлов. Основные события:

  • load — стиль загружен
  • idle — отсутствуют активные тайлы и анимации
  • render — кадр перерисован
  • data — обновление источников данных

В E2E тестах ключевым состоянием считается idle, поскольку оно сигнализирует о завершении асинхронного рендеринга.

Типичный паттерн ожидания:

map.on('load', () => {
  map.on('idle', () => {
    // карта полностью готова
  });
});

Проблема асинхронности тайлов

Карты в Mapbox GL JS используют тайловую модель:

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

Это создаёт неопределённость во времени готовности UI. Поэтому в E2E сценариях нельзя опираться только на фиксированные задержки (setTimeout), так как они приводят к нестабильным тестам.


Cypress в E2E тестировании карт

Cypress часто применяется для тестирования интерфейсов с картами благодаря управлению сетью и DOM.

Ключевые приёмы:

Перехват сетевых запросов

cy.intercept('GET', '**/tiles/**', {
  fixture: 'tiles.json'
}).as('tiles');

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

Ожидание готовности карты

cy.window().then((win) => {
  return new Cypress.Promise((resolve) => {
    win.map.on('idle', resolve);
  });
});

Снимки canvas

Так как Mapbox GL JS рендерит в canvas, проверка часто выполняется через визуальные снапшоты:

cy.get('canvas').screenshot();

Playwright и управление рендером

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

Преимущества:

  • управление ожиданиями сети
  • доступ к Chromium GPU-рендеру
  • стабильные скриншоты

Ожидание полной загрузки карты

await page.waitForFunction(() => {
  return window.map && window.map.loaded();
});

Визуальная проверка

await expect(page.locator('canvas')).toHaveScreenshot();

Playwright особенно полезен для регрессионного тестирования визуальных изменений стиля в Mapbox GL JS.


Selenium и ограничения WebGL

Selenium применяется реже, поскольку:

  • сложнее работать с canvas
  • слабая поддержка GPU-рендеринга
  • нестабильные скриншоты в headless-режиме

Тем не менее Selenium используется в legacy-инфраструктурах, где уже построены большие тестовые наборы.


Визуальная регрессия карт

Основной подход к проверке корректности отображения карт в Mapbox GL JS — snapshot testing.

Суть:

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

Инструменты:

  • Percy
  • Applitools
  • встроенные snapshot-механизмы Playwright

Проблемы визуальной регрессии:

  • антиалиасинг различается между GPU
  • шрифты рендерятся по-разному
  • незначительные сдвиги тайлов

Управление тайлами и стабилизация окружения

Стабильность E2E тестов для Mapbox GL JS достигается через:

  • фиксацию URL источников тайлов
  • использование mock-серверов
  • отключение анимаций

Пример отключения анимаций:

map.setPrefersReducedMotion(true);

или через стили:

map.setStyle({
  ...style,
  transition: {
    duration: 0
  }
});

Проверка взаимодействий с картой

E2E тесты включают сценарии:

  • zoom in / zoom out
  • pan (перемещение)
  • click по слоям
  • hover по объектам

Пример:

map.on('load', () => {
  map.zoomTo(10);
  map.panBy([100, 0]);
});

В Cypress:

cy.get('canvas').trigger('mousedown', { which: 1 })
  .trigger('mousemove', { clientX: 200, clientY: 200 })
  .trigger('mouseup');

Сетевой контроль и изоляция данных

Для стабильности тестов Mapbox GL JS важно контролировать:

  • загрузку стилей JSON
  • запросы vector tiles
  • шрифты glyphs
  • sprites

Стратегии:

  • фикстуры (fixtures)
  • локальные mock-серверы
  • запись и воспроизведение запросов

Headless-режим и проблемы рендеринга

Headless-браузеры могут по-разному рендерить WebGL:

  • различия в GPU emulation
  • отключённые ускорения
  • нестабильные кадры canvas

В Playwright используется:

chromium.launch({ headless: true, args: ['--use-gl=swiftshader'] });

Это улучшает стабильность рендеринга карт в Mapbox GL JS.


Тестирование слоёв и источников данных

Карты состоят из:

  • sources (GeoJSON, vector tiles)
  • layers (fill, line, symbol, circle)

Проверки:

  • наличие слоя
  • правильный порядок слоёв
  • корректные фильтры
map.getLayer('cities-layer');
map.getSource('cities-source');

Асинхронная стабилизация состояния карты

Ключевой паттерн E2E:

  • ожидание load
  • ожидание idle
  • проверка canvas
await new Promise(resolve => {
  map.on('idle', resolve);
});

Это критично для Mapbox GL JS, где рендеринг продолжается после завершения DOM-ready.


Типовые источники нестабильности тестов

  • задержки CDN тайлов
  • разная геометрия GPU
  • анимации переходов
  • конкурентные запросы источников
  • фрагментация сетевых ответов

Стратегии повышения детерминированности

Используемые подходы:

  • фиксация viewport
  • отключение анимаций
  • мокирование всех внешних источников
  • ожидание idle
  • стабилизация шрифтов и sprite sheet

Роль E2E в архитектуре картографических приложений

E2E тестирование для Mapbox GL JS выполняет функции:

  • контроль визуальной консистентности
  • проверка интеграции слоёв и данных
  • выявление регресса рендеринга
  • валидация интерактивных сценариев

Оно дополняет unit-тесты логики и интеграционные проверки API источников данных.