5a4d560e70
- ProtectedRoute: loading -> спиннер, !user -> /login, иначе children - LoginPage/RegisterPage: field+react-hook-form/zod, ошибка через role=alert, редирект на /domains при успехе/уже авторизован - main.tsx: AuthProvider + QueryCache/MutationCache onError -> notifyUnauthorized на UnauthorizedError (сброс сессии из кода вне React-дерева) - AuthContext: logout и notifyUnauthorized чистят react-query кэш (qc.clear()) - Layout: email пользователя + кнопка Выйти - App: /login и /register публичные (авторизованный -> /domains), остальное под ProtectedRoute Починка page-тестов (Accounts/Domains/Templates/DomainDiff/App): AuthProvider + мок api.auth.me, спай-ассерты обновлены под projectId-первым-аргументом сигнатур api.* (T5).
58 lines
1.9 KiB
TypeScript
58 lines
1.9 KiB
TypeScript
import { render, screen } from "@testing-library/react"
|
|
import { MemoryRouter, Routes, Route } from "react-router-dom"
|
|
import { describe, it, expect, vi } from "vitest"
|
|
import { ProtectedRoute } from "./ProtectedRoute"
|
|
import * as AuthContextModule from "./AuthContext"
|
|
|
|
function renderWithAuth(authValue: Partial<AuthContextModule.AuthContextValue>) {
|
|
vi.spyOn(AuthContextModule, "useAuth").mockReturnValue({
|
|
user: null,
|
|
project: null,
|
|
loading: false,
|
|
login: vi.fn(),
|
|
register: vi.fn(),
|
|
logout: vi.fn(),
|
|
...authValue,
|
|
})
|
|
|
|
return render(
|
|
<MemoryRouter initialEntries={["/domains"]}>
|
|
<Routes>
|
|
<Route path="/login" element={<div>login page</div>} />
|
|
<Route
|
|
path="/domains"
|
|
element={
|
|
<ProtectedRoute>
|
|
<div>protected content</div>
|
|
</ProtectedRoute>
|
|
}
|
|
/>
|
|
</Routes>
|
|
</MemoryRouter>,
|
|
)
|
|
}
|
|
|
|
describe("ProtectedRoute", () => {
|
|
it("показывает спиннер, пока идёт проверка сессии", () => {
|
|
renderWithAuth({ user: null, loading: true })
|
|
|
|
expect(screen.queryByText("protected content")).not.toBeInTheDocument()
|
|
expect(screen.queryByText("login page")).not.toBeInTheDocument()
|
|
expect(screen.getByRole("status")).toBeInTheDocument()
|
|
})
|
|
|
|
it("редиректит на /login, когда пользователь не авторизован", () => {
|
|
renderWithAuth({ user: null, loading: false })
|
|
|
|
expect(screen.getByText("login page")).toBeInTheDocument()
|
|
expect(screen.queryByText("protected content")).not.toBeInTheDocument()
|
|
})
|
|
|
|
it("рендерит children, когда пользователь авторизован", () => {
|
|
renderWithAuth({ user: { id: "u1", email: "a@b.com" }, loading: false })
|
|
|
|
expect(screen.getByText("protected content")).toBeInTheDocument()
|
|
expect(screen.queryByText("login page")).not.toBeInTheDocument()
|
|
})
|
|
})
|