Визуальное регрессионное тестирование для Kepler.gl представляет собой проверку стабильности визуального результата картографических слоёв и интерфейса при изменениях кода, данных или окружения рендера. В отличие от классических unit-тестов, здесь объектом контроля становится изображение: карта, её слои, подписи, легенды, взаимодействие цветов, шрифтов и геометрии.
Геовизуализация отличается высокой чувствительностью к изменениям рендера. Даже незначительные модификации могут приводить к визуальным сдвигам:
Kepler.gl использует WebGL через Mapbox GL стек, поэтому детерминированность изображения не гарантируется без дополнительных ограничений. Визуальное регрессионное тестирование фиксирует «эталонный кадр» и сравнивает его с текущим состоянием.
Базовая модель тестирования:
Ключевое требование — воспроизводимость состояния карты.
WebGL не гарантирует идентичность пикселей на разных устройствах. Даже одинаковые шейдеры могут давать различия из-за:
Карта может зависеть от:
Любая асинхронность делает тест нестабильным без мокирования.
Малейшее изменение:
приводит к полностью отличающемуся изображению.
Типичная структура визуального тестирования Kepler.gl:
tests/
visual/
fixtures/
snapshots/
configs/
helpers/
Компоненты:
Для стабильных тестов необходимо жёстко зафиксировать:
const MAP_CONFIG = {
latitude: 37.7749,
longitude: -122.4194,
zoom: 10,
pitch: 0,
bearing: 0
};
Используется фиксированная версия map style:
Все входные данные должны быть статичными:
На практике используются несколько подходов.
Один из наиболее распространённых вариантов:
jest-image-snapshotpixelmatchsharp для обработки изображенийПример базового теста:
import { toMatchImageSnapshot } from 'jest-image-snapshot';
expect.extend({ toMatchImageSnapshot });
test('kepler map render', async () => {
const image = await renderKeplerMap(config, data);
expect(image).toMatchImageSnapshot({
failureThreshold: 0.01,
failureThresholdType: 'percent'
});
});
Чаще всего используется:
Принцип:
Пример:
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('http://localhost:3000');
await page.evaluate((config, data) => {
window.renderKepler(config, data);
}, config, data);
await page.waitForSelector('.kepler-gl-container');
const screenshot = await page.screenshot();
Для повышения стабильности:
await page.emulateMedia({ reducedMotion: 'reduce' });
Визуальные тесты часто нестабильны без нормализации.
Используется для динамических элементов:
Пример логики:
const diffOptions = {
mask: [
{ x: 10, y: 10, width: 100, height: 50 }
]
};
{
threshold: 0.02
}
Позволяет игнорировать мелкие артефакты рендера.
Наиболее популярные библиотеки:
pixelmatchresemble.jsАлгоритм:
const diffPixels = pixelmatch(
img1.data,
img2.data,
diff.data,
width,
height,
{ threshold: 0.1 }
);
Для Kepler.gl критично:
Иногда используется патч:
HTMLCanvasElement.prototype.getContext = function(type) {
if (type === 'webgl') {
return originalGetContext(type, { preserveDrawingBuffer: true });
}
return originalGetContext(type);
};
В CI pipeline визуальные тесты выполняются после сборки:
- name: Run visual tests
run: npm run test:visual
- name: Upload diff artifacts
uses: actions/upload-artifact@v3
with:
name: visual-diffs
path: tests/visual/__diff_output__
Важно:
Любое изменение:
может требовать обновления baseline.
Практика:
__snapshots__/v1__snapshots__/v2или семантические версии тестов.
Каждый слой требует отдельной стратегии:
Различия в font rendering могут ломать тесты.
Решения:
Визуальные тесты дорогие по времени, поэтому применяются:
Для сложных картографических систем применяются комбинированные подходы:
Эталонные изображения формируются:
Визуальное регрессионное тестирование в Kepler.gl становится не вспомогательным инструментом, а обязательной частью контроля качества при работе с WebGL-картографией, где малейшие изменения в графическом пайплайне приводят к каскадным визуальным эффектам, требующим строгой фиксации поведения рендера.