В процессе тестирования React-приложений часто возникает необходимость проверить, как компоненты ведут себя при перенаправлениях. Это может быть связано с различными сценариями, такими как изменение маршрута после успешной отправки формы, перенаправление с ошибкой 404 или редирект по бизнес-логике. В React Testing Library существует несколько подходов для тестирования таких случаев.
MemoryRouterДля тестирования перенаправлений в React-приложениях, использующих
библиотеку react-router-dom, важно правильно настроить
маршрутизацию. В случае с React Testing Library это достигается с
помощью компонента MemoryRouter.
MemoryRouter позволяет эмулировать поведение маршрутов в
тестах без необходимости взаимодействовать с реальной навигацией в
браузере. Он сохраняет состояние маршрутов в памяти, что делает его
идеальным для тестирования логики редиректов.
Пример настройки маршрутизатора в тестах:
import { render } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import MyComponent from './MyComponent';
test('редирект после логина', () => {
render(
<MemoryRouter initialEntries={['/login']}>
<MyComponent />
</MemoryRouter>
);
// здесь можно тестировать поведение компонента
});
useHistory или
useNavigateReact Router предоставляет хук useHistory (до версии 6)
и useNavigate (начиная с версии 6) для программного
перенаправления пользователей на другой маршрут. В тестах нужно
проверить, что редирект происходит корректно.
Для тестирования редиректов важно отслеживать изменения маршрута.
MemoryRouter помогает задать начальный путь, но сам
редирект нужно имитировать с помощью соответствующего хука.
Пример с использованием useNavigate в React Router
v6:
import { render, screen, fireEvent } from '@testing-library/react';
import { MemoryRouter, Routes, Route, useNavigate } from 'react-router-dom';
function LoginComponent() {
const navigate = useNavigate();
const handleLogin = () => {
// логика логина, затем редирект
navigate('/dashboard');
};
return <button onCl ick={handleLogin}>Войти</button>;
}
function Dashboard() {
return <h1>Добро пожаловать на панель управления!</h1>;
}
test('редирект после клика на кнопку', () => {
render(
<MemoryRouter initialEntries={['/login']}>
<Routes>
<Route path="/login" element={<LoginComponent />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</MemoryRouter>
);
fireEvent.click(screen.getByText('Войти'));
expect(screen.getByText('Добро пожаловать на панель управления!')).toBeInTheDocument();
});
Этот пример демонстрирует, как происходит редирект с маршрута
/login на маршрут /dashboard после нажатия
кнопки. В тестах важно убедиться, что новый маршрут отобразился
корректно.
waitFor и
findByИногда в процессе тестирования нужно подождать, пока произойдут
асинхронные действия, такие как загрузка данных или ожидание ответа от
сервера. В таких случаях можно использовать утилиты waitFor
и findBy из React Testing Library.
Пример:
import { render, screen, waitFor } from '@testing-library/react';
import { MemoryRouter, Routes, Route, useNavigate } from 'react-router-dom';
function LoginComponent() {
const navigate = useNavigate();
const handleLogin = async () => {
// имитируем асинхронный процесс логина
await new Promise(resolve => setTimeout(resolve, 1000));
navigate('/dashboard');
};
return <button onCl ick={handleLogin}>Войти</button>;
}
function Dashboard() {
return <h1>Добро пожаловать на панель управления!</h1>;
}
test('редирект после асинхронной операции', async () => {
render(
<MemoryRouter initialEntries={['/login']}>
<Routes>
<Route path="/login" element={<LoginComponent />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</MemoryRouter>
);
fireEvent.click(screen.getByText('Войти'));
await waitFor(() => screen.getByText('Добро пожаловать на панель управления!'));
expect(screen.getByText('Добро пожаловать на панель управления!')).toBeInTheDocument();
});
Здесь мы используем waitFor, чтобы дождаться окончания
асинхронной операции перед проверкой наличия элемента на странице. Это
особенно полезно при тестировании перенаправлений, которые зависят от
внешних факторов.
В некоторых случаях перенаправление может быть связано с ошибкой, например, при попытке перейти на несуществующий маршрут. В таких случаях важно проверить, что приложение корректно обрабатывает ошибку 404 или другие редиректы.
Пример с тестированием страницы с ошибкой 404:
import { render, screen } from '@testing-library/react';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
function NotFound() {
return <h1>Страница не найдена</h1>;
}
test('редирект на страницу 404 при неправильном маршруте', () => {
render(
<MemoryRouter initialEntries={['/unknown']}>
<Routes>
<Route path="*" element={<NotFound />} />
</Routes>
</MemoryRouter>
);
expect(screen.getByText('Страница не найдена')).toBeInTheDocument();
});
В данном примере тестируется поведение приложения при переходе по несуществующему маршруту. Мы ожидаем, что пользователь будет перенаправлен на страницу с ошибкой 404.
В некоторых приложениях редирект может зависеть от состояния компонента или глобального состояния, например, состояния авторизации. Для таких случаев важно проверить, что редирект происходит только при определенных условиях.
Пример с редиректом при отсутствии авторизации:
import { render, screen } from '@testing-library/react';
import { MemoryRouter, Routes, Route, useNavigate } from 'react-router-dom';
function ProtectedPage() {
const navigate = useNavigate();
const isAuthenticated = false; // состояние авторизации
if (!isAuthenticated) {
navigate('/login');
}
return <h1>Защищенная страница</h1>;
}
function LoginPage() {
return <h1>Страница входа</h1>;
}
test('редирект на страницу входа при отсутствии авторизации', () => {
render(
<MemoryRouter initialEntries={['/protected']}>
<Routes>
<Route path="/protected" element={<ProtectedPage />} />
<Route path="/login" element={<LoginPage />} />
</Routes>
</MemoryRouter>
);
expect(screen.getByText('Страница входа')).toBeInTheDocument();
});
Здесь проверяется, что пользователь будет перенаправлен на страницу входа, если он не авторизован.
Тестирование перенаправлений в React-приложениях — это важная часть
обеспечения корректности маршрутизации и пользовательского опыта.
Использование MemoryRouter и хуков маршрутизации, таких как
useNavigate, позволяет эффективно моделировать и
тестировать перенаправления в различных сценариях. Важно учитывать как
синхронные, так и асинхронные редиректы, а также правильно обрабатывать
ошибки и состояния приложения, чтобы гарантировать правильную работу
навигации.