При тестировании Vue-компонентов, содержащих навигационные элементы,
такие как <RouterLink>, важно учитывать, что эти
компоненты зависят от экземпляра маршрутизатора Vue Router. Без
корректной настройки тестовой среды попытки рендеринга компонентов с
<RouterLink> могут привести к ошибкам или
некорректному поведению.
Для изоляции компонента от реального маршрутизатора используется
мокирование. В тестах на основе
vue-test-utils достаточно создать фейковый
экземпляр маршрутизатора:
import { mount } from '@vue/test-utils';
import { createRouter, createWebHistory } from 'vue-router';
import MyComponent from '@/components/MyComponent.vue';
const routes = [
{ path: '/', name: 'Home' },
{ path: '/about', name: 'About' }
];
const router = createRouter({
history: createWebHistory(),
routes
});
router.push('/'); // Начальное состояние маршрута
test('RouterLink рендерится корректно', async () => {
const wrapper = mount(MyComponent, {
global: {
plugins: [router]
}
});
await router.isReady(); // Ждем готовности маршрутизатора
expect(wrapper.find('a').attributes('href')).toBe('/');
});
Ключевой момент — использование router.isReady(). Без
ожидания маршрутизатор может быть не инициализирован, что приведет к
ошибкам при попытке взаимодействия с
<RouterLink>.
Компоненты с <RouterLink> можно тестировать на
корректность навигации. Для этого важно симулировать
клик и убедиться, что маршрут изменился:
test('переход по RouterLink', async () => {
const wrapper = mount(MyComponent, {
global: {
plugins: [router]
}
});
await router.isReady();
const link = wrapper.find('a');
await link.trigger('click');
expect(router.currentRoute.value.fullPath).toBe('/about');
});
При этом <RouterLink> не обязательно рендерится в
реальный <a> тег, если используется
компонентная реализация, поэтому проверка может
включать атрибут to:
expect(wrapper.findComponent({ name: 'RouterLink' }).props('to')).toBe('/about');
В некоторых случаях тестирование компонента не должно зависеть от
реального маршрутизатора. В таких ситуациях удобно мокировать
<RouterLink>, заменяя его простым
компонентом-заглушкой:
const RouterLinkStub = {
props: ['to'],
template: '<a><slot /></a>'
};
const wrapper = mount(MyComponent, {
global: {
stubs: {
RouterLink: RouterLinkStub
}
}
});
expect(wrapper.find('a').exists()).toBe(true);
expect(wrapper.find('a').text()).toBe('Перейти на About');
Такой подход позволяет тестировать визуальное отображение и слоты без необходимости конфигурировать полноценный маршрутизатор.
Для компонентов, которые используют динамические параметры
маршрута, важно правильно мокировать текущий маршрут. Например,
если компонент получает id из URL:
import { createRouter, createWebHistory } from 'vue-router';
const routes = [
{ path: '/user/:id', name: 'User' }
];
const router = createRouter({
history: createWebHistory(),
routes
});
router.push('/user/42');
const wrapper = mount(UserProfile, {
global: {
plugins: [router]
}
});
await router.isReady();
expect(wrapper.vm.$route.params.id).toBe('42');
Это позволяет проверять отображение данных, зависящих от параметров маршрута, без необходимости запускать полноценное приложение.
Для более сложных тестов полезно использовать реальный экземпляр маршрутизатора, чтобы проверить навигацию между компонентами:
const wrapper = mount(App, {
global: {
plugins: [router]
}
});
await router.isReady();
await wrapper.find('a[href="/about"]').trigger('click');
expect(wrapper.html()).toContain('Страница About');
Здесь проверяется не только <RouterLink>, но и то,
что рендерится соответствующий компонент при смене маршрута.
router.isReady() перед взаимодействием с
компонентами, зависящими от маршрутизатора.<RouterLink> для
юнит-тестов, чтобы тест был независимым и быстрым.router.currentRoute.value.to, так и реальные клики по
ссылкам, чтобы убедиться в правильной интеграции маршрутизатора и
компонентов.Эти методы позволяют обеспечить полное покрытие компонентов, работающих с навигацией, и избежать неожиданных ошибок при изменениях маршрутов.