При разработке современных веб-приложений на JavaScript часто возникает необходимость тестирования компонентов, которые зависят от маршрутизации. TanStack Router предоставляет мощный и гибкий способ управления маршрутами, и корректное тестирование компонентов, использующих маршруты, требует понимания особенностей этой библиотеки.
Для тестирования компонентов, зависящих от TanStack Router, ключевым
моментом является создание тестового окружения с имитацией
маршрутов. TanStack Router предоставляет объект
Router, который можно использовать в тестах:
import { createRouter, RouterProvider } from '@tanstack/router';
import { render } from '@testing-library/react';
import App from './App';
const testRouter = createRouter({
routeTree: [
{
path: '/',
component: App,
},
{
path: '/profile/:id',
component: Profile,
},
],
});
render(
<RouterProvider router={testRouter}>
<App />
</RouterProvider>
);
Ключевой момент: оборачивать тестируемый компонент в
RouterProvider с тестовым экземпляром
маршрутизатора, чтобы маршруты работали так же, как в реальном
приложении.
navigate и проверка переходовTanStack Router использует функцию navigate для
изменения маршрутов. В тестах можно эмулировать
навигацию и проверять, как компонент реагирует на изменение
пути:
import { act } from '@testing-library/react';
act(() => {
testRouter.navigate('/profile/42');
});
После вызова navigate состояние маршрутизатора
обновляется, и тестируемый компонент получает новые параметры маршрута.
Это позволяет проверять:
params).Компоненты часто зависят от динамических сегментов маршрута, например
/profile/:id. В TanStack Router эти значения доступны через
объект useParams:
import { useParams } from '@tanstack/router';
function Profile() {
const { id } = useParams();
return <div>Profile ID: {id}</div>;
}
В тестах важно эмулировать параметры маршрута, чтобы убедиться, что компонент корректно их использует:
testRouter.navigate('/profile/123');
const { getByText } = render(
<RouterProvider router={testRouter}>
<Profile />
</RouterProvider>
);
expect(getByText('Profile ID: 123')).toBeInTheDocument();
TanStack Router хранит состояние, которое можно использовать для проверки в тестах:
router.state.currentLocation — текущий путь.router.state.matches — список всех активных
маршрутов.Пример проверки перехода:
act(() => {
testRouter.navigate('/profile/7');
});
expect(testRouter.state.currentLocation.pathname).toBe('/profile/7');
expect(testRouter.state.matches.some(match => match.route.path === '/profile/:id')).toBe(true);
Это позволяет удостовериться, что переход произошёл правильно, а маршрутизатор корректно сопоставил путь с маршрутом.
TanStack Router поддерживает асинхронные функции loader
для предзагрузки данных перед рендером компонента. В тестах необходимо
использовать async/await и проверять загрузку данных:
const profileRoute = {
path: '/profile/:id',
component: Profile,
loader: async ({ params }) => {
return fetch(`/api/profile/${params.id}`).then(res => res.json());
},
};
await act(async () => {
await testRouter.navigate('/profile/5');
});
expect(fetch).toHaveBeenCalledWith('/api/profile/5');
Важно эмулировать ответы API через моки, чтобы тесты были детерминированными.
Для комплексного тестирования часто создают интеграционные тесты, где проверяются:
Link или
navigate).loader.Пример:
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
render(
<RouterProvider router={testRouter}>
<App />
</RouterProvider>
);
userEvent.click(screen.getByText('Go to Profile'));
expect(testRouter.state.currentLocation.pathname).toBe('/profile/1');
expect(screen.getByText('Profile ID: 1')).toBeInTheDocument();
Этот подход позволяет тестировать приложение максимально близко к реальному поведению, включая взаимодействие с маршрутизатором и переходы между страницами.
Для упрощения тестов создают вспомогательные функции:
renderWithRouter — обёртка для
тестирования компонентов с маршрутизатором.navigateTo — функция для быстрого
перехода на нужный маршрут.mockLoader — эмуляция асинхронных
загрузок данных.Пример обёртки:
function renderWithRouter(ui, { route = '/' } = {}) {
testRouter.navigate(route);
return render(<RouterProvider router={testRouter}>{ui}</RouterProvider>);
}
Это делает тесты более читаемыми и уменьшает повторение кода.
Если приложение использует авторизацию или защиту маршрутов, необходимо:
testRouter.navigate('/admin');
expect(testRouter.state.currentLocation.pathname).toBe('/login');
TanStack Router позволяет легко интегрировать такие проверки через
loader или beforeEnter хуки.
Эти методы обеспечивают надежное и детерминированное тестирование компонентов, зависящих от TanStack Router, включая динамические маршруты, асинхронные данные и защиту маршрутов.