Мок Vue Router в тестах

При тестировании компонентов Vue, которые используют Vue Router для навигации или работы с маршрутами, часто возникает необходимость изолировать компонент от реального роутера. Это позволяет проверять поведение компонента без создания полного приложения или зависимости от состояния маршрутов. В таких случаях используется мок (mock) Vue Router.


Подключение Vue Test Utils и создание мока

Для начала необходимы базовые импорты:

import { mount } from '@vue/test-utils';
import { createRouter, createWebHistory } from 'vue-router';
import ComponentUnderTest from '@/components/ComponentUnderTest.vue';

Мок роутера можно реализовать несколькими способами: полностью эмулировать объект router, либо создать реальный роутер с ограниченным набором маршрутов.

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

const mockRouter = {
  push: jest.fn(),
  replace: jest.fn(),
  currentRoute: {
    value: { path: '/home' }
  }
};

Здесь ключевое:

  • push и replace — методы навигации, которые можно отслеживать через Jest.
  • currentRoute.value — объект текущего маршрута, аналогичный объекту route в Vue Router 4.

Монтирование компонента с моком роутера

Для передачи мока в компонент используется опция global.plugins или global.mocks:

const wrapper = mount(ComponentUnderTest, {
  global: {
    mocks: {
      $router: mockRouter,
      $route: mockRouter.currentRoute
    }
  }
});

Варианты:

  • $router — предоставляет доступ к методам навигации.
  • $route — содержит данные текущего маршрута (params, query, name, path).

После этого можно проверять вызовы методов:

await wrapper.find('button.navigate').trigger('click');
expect(mockRouter.push).toHaveBeenCalledWith('/about');

Создание реального, но ограниченного роутера

Иногда требуется протестировать реакцию компонента на реальные переходы или guards. Для этого создаётся роутер с минимальными маршрутами:

const routes = [
  { path: '/home', component: { template: '<div>Home</div>' } },
  { path: '/about', component: { template: '<div>About</div>' } }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

Компонент монтируется с настоящим роутером:

const wrapper = mount(ComponentUnderTest, {
  global: {
    plugins: [router]
  }
});

Навигация может быть смоделирована через router.push и router.replace:

await router.push('/about');
await router.isReady();
expect(wrapper.html()).toContain('About');

Такой подход полезен, если компонент использует watch на route или navigation guards.


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

Проверка компонентов, зависящих от динамических параметров маршрута (params) или query-параметров, требует настройки $route:

const wrapper = mount(ComponentUnderTest, {
  global: {
    mocks: {
      $route: {
        params: { id: '123' },
        query: { ref: 'abc' }
      }
    }
  }
});

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

expect(wrapper.vm.$route.params.id).toBe('123');
expect(wrapper.vm.$route.query.ref).toBe('abc');

Отслеживание навигации через методы роутера

Для проверки того, что компонент инициирует переход, используется мок push или replace:

const mockRouter = { push: jest.fn() };

const wrapper = mount(ComponentUnderTest, {
  global: {
    mocks: { $router: mockRouter }
  }
});

wrapper.find('button.go-to-profile').trigger('click');

expect(mockRouter.push).toHaveBeenCalledWith({ name: 'Profile', params: { userId: 1 } });

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


Мок навигационных guards

Если компонент использует guards типа beforeRouteEnter, beforeRouteUpdate или beforeRouteLeave, их можно протестировать через мок:

const mockNext = jest.fn();

ComponentUnderTest.beforeRouteEnter({ path: '/login' }, null, mockNext);

expect(mockNext).toHaveBeenCalled();

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

  • Использовать мок объектов, когда требуется проверить вызовы методов без реального роутера.
  • Использовать ограниченный реальный роутер, когда важна реакция компонента на изменения маршрутов.
  • Всегда устанавливать await router.isReady() при работе с настоящим роутером в тестах, чтобы избежать ошибок из-за асинхронной инициализации.
  • Для параметров маршрута и query лучше применять мок через $route, чтобы не зависеть от глобального состояния.

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