Моки геолокации

Основные принципы

Моки геолокации позволяют эмулировать поведение API браузера navigator.geolocation, подменяя реальные координаты пользователя на заданные значения. Это особенно полезно для тестирования функционала, который зависит от местоположения, например, карт, сервисов доставки или поиска ближайших объектов. Cypress не предоставляет встроенной команды для работы с геолокацией напрямую, поэтому подмена осуществляется через стаббы и перехват методов браузера.

Работа с navigator.geolocation

API геолокации включает два ключевых метода:

  • getCurrentPosition(successCallback, errorCallback, options) — получает текущие координаты.
  • watchPosition(successCallback, errorCallback, options) — отслеживает изменения позиции в реальном времени.

Для мокирования чаще всего используется getCurrentPosition. Cypress позволяет переопределять поведение объекта через cy.visit() с параметром onBeforeLoad, который даёт доступ к объекту window перед загрузкой страницы.

Подмена координат через cy.visit

Пример подмены координат на фиксированные значения:

cy.visit('/map', {
  onBeforeLoad(win) {
    const mockPosition = {
      coords: {
        latitude: 55.751244,
        longitude: 37.618423,
        accuracy: 100
      }
    };

    cy.stub(win.navigator.geolocation, 'getCurrentPosition')
      .callsFake((success) => success(mockPosition));
  }
});

Разбор кода:

  • onBeforeLoad(win) позволяет вмешаться в объект window до инициализации скриптов страницы.
  • cy.stub() создаёт стаб для метода getCurrentPosition.
  • callsFake заменяет вызов на пользовательскую функцию, передающую фиктивные координаты.
  • mockPosition содержит latitude, longitude и accuracy. При необходимости можно добавить altitude, altitudeAccuracy, heading, speed.

Обработка ошибок геолокации

Для проверки поведения приложения при отказе в доступе к геопозиции используется errorCallback:

cy.visit('/map', {
  onBeforeLoad(win) {
    cy.stub(win.navigator.geolocation, 'getCurrentPosition')
      .callsFake((success, error) => {
        error({ code: 1, message: 'User denied Geolocation' });
      });
  }
});

code может принимать значения:

  • 1 — PERMISSION_DENIED
  • 2 — POSITION_UNAVAILABLE
  • 3 — TIMEOUT

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

Динамическая смена координат

Иногда требуется тестировать реакции приложения на изменение позиции. Для этого можно комбинировать cy.stub с генерацией случайных или последовательных координат:

let positions = [
  { latitude: 55.751244, longitude: 37.618423 },
  { latitude: 59.934280, longitude: 30.335099 }
];

cy.visit('/map', {
  onBeforeLoad(win) {
    let callCount = 0;
    cy.stub(win.navigator.geolocation, 'getCurrentPosition')
      .callsFake((success) => {
        success({
          coords: {
            latitude: positions[callCount].latitude,
            longitude: positions[callCount].longitude,
            accuracy: 50
          }
        });
        callCount++;
      });
  }
});

При каждом вызове getCurrentPosition возвращаются новые координаты, что позволяет тестировать перемещения пользователя.

Моки для watchPosition

watchPosition возвращает идентификатор, который можно использовать для остановки наблюдения через clearWatch. Мокирование аналогично getCurrentPosition, с добавлением возможности вызывать successCallback несколько раз:

cy.visit('/map', {
  onBeforeLoad(win) {
    cy.stub(win.navigator.geolocation, 'watchPosition')
      .callsFake((success) => {
        const positions = [
          { latitude: 55.751244, longitude: 37.618423 },
          { latitude: 55.752000, longitude: 37.620000 }
        ];
        positions.forEach(pos => success({ coords: pos }));
        return 1; // id watch
      });
  }
});

Это позволяет имитировать перемещение пользователя по маршруту без реальной смены геопозиции.

Практические советы

  1. Стабирование до загрузки страницы: обязательно использовать onBeforeLoad, иначе скрипты страницы вызовут оригинальный метод до подмены.
  2. Совместимость с TypeScript: при строгой типизации нужно расширять Navigator интерфейсом, добавляя stub для методов.
  3. Тесты отказов и ошибок: важно проверять поведение UI при PERMISSION_DENIED и других кодах ошибок.
  4. Тестирование динамики: watchPosition подходит для имитации перемещений и маршрутов, но следует учитывать, что Cypress работает в одном потоке, поэтому последовательные вызовы могут быть синхронными.

Интеграция с другими тестами

Моки геолокации часто комбинируются с перехватом сетевых запросов (cy.intercept) для проверки реакций приложения на данные, связанные с местоположением, например, получение ближайших объектов или расчёт маршрута. Это создаёт полноценный сценарий тестирования геофункционала без зависимости от реального устройства или VPN.