createRouter для тестов

При тестировании компонентов Vue, которые зависят от маршрутизации, критически важно корректно настроить экземпляр маршрутизатора. Vue Router в сочетании с Vue Test Utils позволяет создавать локальные маршрутизаторы, имитировать навигацию и проверять поведение компонентов при смене маршрутов.


Импорт необходимых модулей

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

import { createRouter, createWebHistory } from 'vue-router';
import { mount } from '@vue/test-utils';
import ComponentUnderTest from '@/components/ComponentUnderTest.vue';
  • createRouter — функция для создания экземпляра маршрутизатора.
  • createWebHistory — стратегия истории браузера для маршрутов.
  • mount — метод из Vue Test Utils для монтирования компонентов в тестах.

Создание локального маршрутизатора

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

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

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

Особенности:

  • routes содержит только маршруты, необходимые для теста.
  • Компоненты можно заменять простыми заглушками (template: '<div>...</div>') для ускорения тестирования.
  • История (history) не обязательно должна совпадать с основной; для юнит-тестов подойдет createMemoryHistory для имитации истории без влияния на браузер.

Инициализация маршрутизатора перед монтированием

Прямое монтирование компонента без инициализации маршрутизатора приведет к ошибкам при доступе к $router или $route. Важно сначала выполнить router.isReady():

await router.isReady();

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

Пояснение:

  • router.isReady() гарантирует, что начальный маршрут корректно загружен.
  • Опция global.plugins передает роутер в контекст компонента так же, как он используется в приложении.

Тестирование переходов между маршрутами

Для проверки навигации можно использовать метод router.push:

await router.push('/about');
await wrapper.vm.$nextTick();

expect(wrapper.html()).toContain('About');

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

  • router.push изменяет маршрут программно.
  • await wrapper.vm.$nextTick() нужен для обновления DOM после изменения маршрута.
  • Содержимое компонента можно проверять через wrapper.html() или wrapper.text().

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

Иногда требуется проверить реакцию компонента на параметры:

await router.push({ name: 'About', query: { ref: 'test' } });
await wrapper.vm.$nextTick();

expect(wrapper.vm.$route.query.ref).toBe('test');
  • $route.params используется для динамических сегментов пути (/user/:id).
  • $route.query хранит query-параметры, например ?ref=test.

Использование фабрик для повторного создания роутера

Для крупных тестов удобно создавать функцию-фабрику:

function createTestRouter(initialRoute = '/') {
  const routes = [
    { path: '/', name: 'Home', component: { template: '<div>Home</div>' } },
    { path: '/about', name: 'About', component: { template: '<div>About</div>' } },
  ];

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

  router.push(initialRoute);

  return router;
}
  • Позволяет быстро менять начальный маршрут для разных тестов.
  • Изоляция маршрутов предотвращает влияние одного теста на другой.

Vue Test Utils корректно обрабатывает <router-view> и <router-link> при подключении локального маршрутизатора:

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

const link = wrapper.findComponent({ name: 'RouterLink' });
await link.trigger('click');

expect(router.currentRoute.value.path).toBe('/about');
  • Компоненты <router-link> можно имитировать кликом через trigger('click').
  • Текущий маршрут доступен через router.currentRoute.value.

Рекомендации по производительности тестов

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

Если требуется, можно расширять фабрики для включения асинхронных маршрутов, lazy-loading компонентов и глобальных guard-ов. Это позволяет тестировать сложные сценарии навигации, авторизации и условного рендеринга компонентов на основе маршрутов.