E2E тесты с картами

E2E-тестирование карт на базе OpenLayers требует учета специфики рендеринга, асинхронной загрузки тайлов, работы canvas и нестабильности сетевых источников. Поведение карты отличается от классических DOM-интерфейсов: результат формируется не только HTML-деревом, но и графическим буфером, который обновляется в ответ на события источников данных и слоя отрисовки.

Сценарии end-to-end тестирования карт обычно строятся вокруг следующих слоев:

  • инициализация карты и контроль состояния view
  • проверка загрузки слоев и тайлов
  • взаимодействие с пользовательскими жестами (pan, zoom)
  • валидация визуального результата через canvas или пиксельные сравнения
  • контроль сетевых запросов к tile-серверам
  • стабилизация асинхронных событий

Ключевое отличие от UI-тестирования форм заключается в том, что карта является высокоасинхронной системой, где итоговое состояние формируется постепенно.

Тестовые фреймворки и окружение

Для E2E тестов карт чаще всего используются:

  • Playwright — обеспечивает контроль браузера, перехват сети, работу с canvas и снапшоты
  • Cypress — удобен для DOM-взаимодействий, но требует дополнительных подходов для canvas
  • Puppeteer — низкоуровневый контроль Chromium

Playwright обеспечивает более предсказуемую работу с асинхронными графическими состояниями, особенно при тестировании WebGL и canvas-рендеринга, характерного для картографических библиотек.

Проблема асинхронного рендеринга карты

Карты в OpenLayers не имеют мгновенного состояния «готово». Даже после события load слоя возможны:

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

Поэтому ключевой задачей тестов становится определение стабильного состояния карты.

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

  • ожидание события rendercomplete
  • ожидание отсутствия активных сетевых запросов
  • проверка состояния источников слоя (source.getState())
  • контроль завершения tile loading

Управление загрузкой тайлов

Карты используют tile-based рендеринг, где изображение формируется из множества HTTP-запросов. Это делает E2E нестабильными без контроля сети.

Основной подход — перехват запросов:

  • блокировка реальных tile-серверов
  • подмена ответов фикстурами
  • эмуляция задержек сети

В Playwright это реализуется через route:

  • перехват URL шаблонов /tile/{z}/{x}/{y}
  • возврат статического изображения
  • контроль времени ответа

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

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

Карта считается стабилизированной, когда:

  • отсутствуют активные tile requests
  • завершен rendercomplete
  • canvas не изменяется между кадрами

Дополнительно применяются проверки:

  • сравнение контрольного snapshot canvas
  • проверка количества вызовов postrender
  • фиксация состояния view (getCenter, getZoom)

В OpenLayers события рендеринга имеют циклический характер, поэтому важно избегать ожиданий фиксированного тайминга.

Работа с canvas и визуальная валидация

Основной рендер карты происходит в <canvas>, что делает невозможным стандартные DOM-assertions.

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

  • pixel diff сравнение (golden images)
  • скриншоты viewport
  • анализ частичных регионов canvas
  • сравнение hash изображения

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

При этом стабильность зависит от:

  • одинаковых размеров viewport
  • фиксированного device pixel ratio
  • отключенных анимаций
  • детерминированных источников данных

Контроль анимаций и переходов

OpenLayers использует анимации для:

  • zoom transitions
  • pan easing
  • rotation

Для тестов они должны быть отключены:

  • view.setAnimate(false) (логически)
  • CSS override для canvas контейнера
  • ускорение таймеров в тестовом окружении

Без этого визуальные проверки становятся недетерминированными.

Пример структуры E2E сценария

import { test, expect } from '@playwright/test';

test('карта загружается и отображает слой', async ({ page }) => {
  await page.route('**/tile/**', route => {
    route.fulfill({
      contentType: 'image/png',
      body: fakeTileBuffer
    });
  });

  await page.goto('http://localhost:3000/map');

  const canvas = page.locator('canvas');

  await expect.poll(async () => {
    return await page.evaluate(() => {
      return window.map?.getLayers().getLength();
    });
  }).toBeGreaterThan(0);

  await expect(canvas).toHaveScreenshot('map-initial.png');
});

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

Основные сценарии взаимодействий:

  • drag (pan)
  • scroll zoom
  • double click zoom
  • pinch (mobile emulation)

Для canvas взаимодействий важно учитывать координаты:

  • расчет центра экрана
  • преобразование в screen pixels
  • симуляция pointer events

Playwright позволяет точно воспроизводить pointer sequence:

  • mouse.down
  • mouse.move
  • mouse.up

После каждого действия требуется ожидание стабилизации рендера карты.

Перехват состояния источников данных

OpenLayers использует Source объекты:

  • XYZ
  • VectorSource
  • WMS

Состояние источника критично для тестов:

  • source.getState() === 'ready'
  • tileLoadFunction завершен
  • vector features загружены

Тесты часто опираются на проверку количества фич:

await page.waitForFunction(() => {
  return window.map.getLayers().item(0)
    .getSource()
    .getFeatures().length > 0;
});

Изоляция данных и фикстуры

Для детерминированных E2E тестов необходимо:

  • фиксировать геоданные (GeoJSON)
  • подменять tile endpoints
  • использовать локальный mock server
  • исключать реальные API зависимости

Особенно важно при работе с vector layers, где порядок и содержимое данных влияет на визуальный результат.

Частые источники нестабильности

Основные причины флаки-тестов:

  • параллельная загрузка тайлов
  • различия в тайловых серверах
  • различия рендеринга canvas между браузерами
  • незафиксированный viewport
  • асинхронные события изменения view

Устранение достигается через:

  • синхронизацию через rendercomplete
  • фиксацию геометрии view
  • отключение анимаций
  • мокирование сети

Проверка координат и преобразований

Критические проверки включают:

  • преобразование координат fromLonLat
  • корректность projection
  • позиционирование объектов на карте

Тесты часто сравнивают:

  • логические координаты
  • экранные пиксели
  • bounding box слоя

Ошибки в проекциях проявляются только на визуальном уровне, что делает E2E единственным надежным способом проверки.

Тестирование слоев и их порядка

Порядок слоев в OpenLayers влияет на итоговый рендер:

  • base layer
  • raster overlays
  • vector overlays

Проверка:

  • порядок в map.getLayers()
  • z-index рендеринга
  • видимость слоев

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

Производительность в E2E сценариях

Карты требуют контроля производительности:

  • количество tile requests
  • время первого render
  • FPS при pan/zoom

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

  • performance.mark
  • performance.measure
  • trace viewer Playwright

При перегрузке слоев тесты фиксируют деградацию рендеринга.

Детализация canvas assertions

Pixel-level проверки применяются для:

  • маркеров
  • кластеров
  • границ полигонов
  • heatmap

Важно учитывать:

  • антиалиасинг
  • различия GPU
  • devicePixelRatio

Поэтому допустимая стратегия — частичное сравнение областей вместо полного canvas diff.

Организация тестового слоя приложения

Для E2E тестируемого приложения обычно вводится режим:

  • deterministic mode
  • static sources
  • disabled animations
  • fixed seed for clustering

Это позволяет стабилизировать поведение карты без изменения бизнес-логики библиотеки OpenLayers.