Защищенные маршруты — это маршруты, доступ к которым должен предоставляться только определенным пользователям, например, аутентифицированным или обладающим конкретными ролями. В React Router реализовать это можно с помощью компонент-оберток и проверки состояния аутентификации.
Для начала создается компонент ProtectedRoute, который
проверяет доступ пользователя:
import { Navigate } from 'react-router-dom';
function ProtectedRoute({ isAuthenticated, children }) {
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return children;
}
isAuthenticated — булевое значение,
определяющее, авторизован ли пользователь.Navigate — компонент React Router,
выполняющий перенаправление при отсутствии доступа.children — защищенный контент, который
отображается только при успешной проверке.Использование в маршрутах:
<Routes>
<Route path="/dashboard" element={
<ProtectedRoute isAuthenticated={user.isLoggedIn}>
<Dashboard />
</ProtectedRoute>
} />
</Routes>
Тестирование защищенных маршрутов направлено на два ключевых аспекта:
Для тестирования можно использовать
React Testing Library вместе с MemoryRouter из
react-router-dom:
import { render, screen } from '@testing-library/react';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
import ProtectedRoute from './ProtectedRoute';
import Dashboard from './Dashboard';
import Login from './Login';
test('показывает Dashboard для авторизованного пользователя', () => {
render(
<MemoryRouter initialEntries={['/dashboard']}>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/dashboard" element={
<ProtectedRoute isAuthenticated={true}>
<Dashboard />
</ProtectedRoute>
} />
</Routes>
</MemoryRouter>
);
expect(screen.getByText(/dashboard/i)).toBeInTheDocument();
});
test('перенаправляет неавторизованного пользователя на Login', () => {
render(
<MemoryRouter initialEntries={['/dashboard']}>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/dashboard" element={
<ProtectedRoute isAuthenticated={false}>
<Dashboard />
</ProtectedRoute>
} />
</Routes>
</MemoryRouter>
);
expect(screen.getByText(/login/i)).toBeInTheDocument();
});
MemoryRouter позволяет имитировать
навигацию в тестах.initialEntries задает начальный путь
маршрутизатора.Если доступ зависит от ролей, ProtectedRoute
расширяется:
function ProtectedRoute({ isAuthenticated, role, allowedRoles, children }) {
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
if (!allowedRoles.includes(role)) {
return <Navigate to="/unauthorized" replace />;
}
return children;
}
Тестирование маршрутов с ролями:
test('пользователь с ролью "admin" получает доступ', () => {
render(
<MemoryRouter initialEntries={['/admin']}>
<Routes>
<Route path="/unauthorized" element={<Unauthorized />} />
<Route path="/admin" element={
<ProtectedRoute isAuthenticated={true} role="admin" allowedRoles={['admin']}>
<AdminPanel />
</ProtectedRoute>
} />
</Routes>
</MemoryRouter>
);
expect(screen.getByText(/admin panel/i)).toBeInTheDocument();
});
test('пользователь с ролью "user" перенаправляется на Unauthorized', () => {
render(
<MemoryRouter initialEntries={['/admin']}>
<Routes>
<Route path="/unauthorized" element={<Unauthorized />} />
<Route path="/admin" element={
<ProtectedRoute isAuthenticated={true} role="user" allowedRoles={['admin']}>
<AdminPanel />
</ProtectedRoute>
} />
</Routes>
</MemoryRouter>
);
expect(screen.getByText(/unauthorized/i)).toBeInTheDocument();
});
MemoryRouter обязательно
для тестов, чтобы не требовался реальный браузер.role и isAuthenticated
помогает выявить ошибки в логике маршрутов.Navigate и MemoryRouter, так как API
может изменяться.Тщательное тестирование защищенных маршрутов гарантирует, что пользователи видят только разрешенный контент, а попытки несанкционированного доступа обрабатываются корректно.