Мокирование навигации

Navigo — это легковесная библиотека для управления маршрутизацией в одностраничных приложениях на JavaScript. При разработке сложных приложений часто возникает необходимость тестировать маршруты и переходы между ними без реального изменения URL браузера или без обращения к серверу. Для этого используется мокирование навигации, которое позволяет имитировать работу роутера в изолированной среде.


Создание экземпляра Navigo для тестов

Для тестирования маршрутов создаётся отдельный экземпляр Navigo. Важно при этом указать правильный базовый путь, если приложение работает не с корня домена:

import Navigo from 'navigo';

const router = new Navigo('/', { hash: true });

Ключевые моменты при создании экземпляра для мокирования:

  • Использование hash режима позволяет избежать реальных изменений URL.
  • Отдельный экземпляр изолирует тестируемую навигацию от основной работы приложения.
  • Можно переопределять методы navigate и resolve, чтобы контролировать переходы.

Мокирование метода navigate

Метод navigate(path, options) выполняет переход к указанному маршруту. Для тестов его часто заменяют на функцию-заглушку:

router.navigate = (path, options) => {
  console.log(`Переход к маршруту: ${path}`, options);
  return Promise.resolve();
};

Такое мокирование позволяет:

  • Отслеживать вызовы маршрутов.
  • Проверять, какие параметры передаются при навигации.
  • Исключить фактическое изменение URL.

Использование spy и stub для мокирования

При интеграционных и модульных тестах удобно использовать библиотеки типа Jest или Sinon:

import sinon from 'sinon';

const navigateSpy = sinon.spy(router, 'navigate');

router.navigate('/home');

console.assert(navigateSpy.calledOnce, 'navigate должен быть вызван один раз');
console.assert(navigateSpy.calledWith('/home'), 'navigate должен быть вызван с /home');

Преимущества использования spy:

  • Автоматическая проверка количества вызовов.
  • Анализ переданных аргументов.
  • Возможность сброса состояния между тестами.

Мокирование обработки маршрутов

Navigo позволяет назначать обработчики маршрутов через метод on. Для тестов эти обработчики заменяют на заглушки:

const homeHandler = jest.fn();
router.on('/home', homeHandler);

router.resolve('/home');

expect(homeHandler).toHaveBeenCalled();

Особенности мокирования обработчиков:

  • resolve(path) инициирует обработку маршрута без фактического перехода.
  • Можно тестировать вызов логики внутри обработчика без внешних эффектов.
  • Обработчики могут возвращать значения для проверки их результата.

Мокирование глобальных переходов

В сложных приложениях часто вызывается window.history.pushState или window.location. Для изоляции тестов эти методы можно переопределять:

const originalPushState = window.history.pushState;
window.history.pushState = jest.fn();

router.navigate('/about');

expect(window.history.pushState).toHaveBeenCalledWith({}, '', '/about');

window.history.pushState = originalPushState;

Зачем это нужно:

  • Избегает реальной навигации в браузере.
  • Позволяет отслеживать вызовы истории.
  • Можно эмулировать различные состояния истории для тестов.

Комбинированное мокирование

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

  1. navigate — для контроля переходов.
  2. on / resolve — для проверки вызова обработчиков.
  3. window.history / window.location — для имитации состояния браузера.

Пример комбинированного подхода:

router.navigate = jest.fn();
const dashboardHandler = jest.fn();
router.on('/dashboard', dashboardHandler);

router.navigate('/dashboard');
router.resolve('/dashboard');

expect(router.navigate).toHaveBeenCalledWith('/dashboard');
expect(dashboardHandler).toHaveBeenCalled();

Практические рекомендации

  • Использовать отдельный экземпляр Navigo для каждого теста, чтобы избежать состояния между тестами.
  • Не модифицировать глобальные методы браузера напрямую, если это не требуется для конкретного теста.
  • Комбинировать мокирование маршрутов и обработчиков для комплексных сценариев.
  • Проверять переданные параметры и количество вызовов, что особенно важно для тестирования динамических маршрутов с параметрами (/user/:id).

Мокирование динамических маршрутов

Navigo поддерживает параметры в маршрутах. Для тестирования это важно:

const userHandler = jest.fn();
router.on('/user/:id', userHandler);

router.resolve('/user/42');

expect(userHandler).toHaveBeenCalled();
expect(userHandler.mock.calls[0][0].params.id).toBe('42');

Ключевые моменты:

  • Параметры передаются в объекте params обработчику.
  • Можно тестировать разные варианты значений параметров без реальной навигации.
  • Это позволяет проверять как обработчик реагирует на различные данные URL.

Тестирование переходов с опциями

Метод navigate принимает объект с опциями, например { updateBrowserURL: false }. При мокировании важно учитывать эти опции:

router.navigate = jest.fn((path, options) => options);

const options = router.navigate('/settings', { updateBrowserURL: false });
expect(options.updateBrowserURL).toBe(false);

Это позволяет:

  • Проверять логику работы маршрутов без изменения URL.
  • Эмулировать поведение роутера в разных режимах (history / hash).
  • Тестировать условные переходы в зависимости от опций.

Итоговая структура мокирования

  1. Создать отдельный экземпляр Navigo.
  2. Мокировать navigate для контроля переходов.
  3. Мокировать обработчики через on и resolve.
  4. При необходимости переопределять методы истории браузера.
  5. Тестировать параметры маршрутов и опции навигации.
  6. Использовать spy/stub для проверки вызовов и аргументов.

Такой подход обеспечивает полное покрытие логики маршрутизации в тестах и позволяет создавать надёжные одностраничные приложения с динамическими маршрутами и сложными переходами.