refactor: rename PublicRoute with AutoRedirectRoute
This commit is contained in:
@@ -3,125 +3,125 @@ import { MemoryRouter, Route, Routes } from "react-router-dom";
|
|||||||
import { beforeEach, describe, expect, it } from "vitest";
|
import { beforeEach, describe, expect, it } from "vitest";
|
||||||
import { mockUser } from "../../test/fixtures/user.fixture";
|
import { mockUser } from "../../test/fixtures/user.fixture";
|
||||||
import { useAuthStore } from "../store/useAuthStore";
|
import { useAuthStore } from "../store/useAuthStore";
|
||||||
import { ProtectedRoute, PublicRoute } from "./RouteGuards";
|
import { ProtectedRoute, AutoRedirectRoute } from "./RouteGuards";
|
||||||
|
|
||||||
function renderGuard(ui: React.ReactNode, mountPath: "/protected" | "/public") {
|
function renderGuard(ui: React.ReactNode, mountPath: "/protected" | "/public") {
|
||||||
return render(
|
return render(
|
||||||
<MemoryRouter initialEntries={[mountPath]}>
|
<MemoryRouter initialEntries={[mountPath]}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/login" element={<div>Login Page</div>} />
|
<Route path="/login" element={<div>Login Page</div>} />
|
||||||
<Route path="/drawer" element={<div>Drawer Page</div>} />
|
<Route path="/drawer" element={<div>Drawer Page</div>} />
|
||||||
<Route path="/protected" element={ui} />
|
<Route path="/protected" element={ui} />
|
||||||
<Route path="/public" element={ui} />
|
<Route path="/public" element={ui} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</MemoryRouter>,
|
</MemoryRouter>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
useAuthStore.setState({
|
useAuthStore.setState({
|
||||||
accessToken: null,
|
accessToken: null,
|
||||||
user: null,
|
user: null,
|
||||||
isInitializing: true,
|
isInitializing: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("ProtectedRoute", () => {
|
describe("ProtectedRoute", () => {
|
||||||
it("should show SplashScreen while auth is initializing", () => {
|
it("should show SplashScreen while auth is initializing", () => {
|
||||||
useAuthStore.setState({
|
useAuthStore.setState({
|
||||||
isInitializing: true,
|
isInitializing: true,
|
||||||
accessToken: null,
|
accessToken: null,
|
||||||
user: null,
|
user: null,
|
||||||
|
});
|
||||||
|
renderGuard(
|
||||||
|
<ProtectedRoute>
|
||||||
|
<div>Secret</div>
|
||||||
|
</ProtectedRoute>,
|
||||||
|
"/protected",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText(/Unsealing/i)).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText("Secret")).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
renderGuard(
|
|
||||||
<ProtectedRoute>
|
|
||||||
<div>Secret</div>
|
|
||||||
</ProtectedRoute>,
|
|
||||||
"/protected",
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(screen.getByText(/Unsealing/i)).toBeInTheDocument();
|
it("should redirect unauthenticated users to /login", () => {
|
||||||
expect(screen.queryByText("Secret")).not.toBeInTheDocument();
|
useAuthStore.setState({
|
||||||
});
|
isInitializing: false,
|
||||||
|
accessToken: null,
|
||||||
it("should redirect unauthenticated users to /login", () => {
|
user: null,
|
||||||
useAuthStore.setState({
|
});
|
||||||
isInitializing: false,
|
renderGuard(
|
||||||
accessToken: null,
|
<ProtectedRoute>
|
||||||
user: null,
|
<div>Secret</div>
|
||||||
|
</ProtectedRoute>,
|
||||||
|
"/protected",
|
||||||
|
);
|
||||||
|
expect(screen.getByText("Login Page")).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText("Secret")).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
renderGuard(
|
|
||||||
<ProtectedRoute>
|
|
||||||
<div>Secret</div>
|
|
||||||
</ProtectedRoute>,
|
|
||||||
"/protected",
|
|
||||||
);
|
|
||||||
expect(screen.getByText("Login Page")).toBeInTheDocument();
|
|
||||||
expect(screen.queryByText("Secret")).not.toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render page for authenticated users", () => {
|
it("should render page for authenticated users", () => {
|
||||||
useAuthStore.setState({
|
useAuthStore.setState({
|
||||||
isInitializing: false,
|
isInitializing: false,
|
||||||
accessToken: "token",
|
accessToken: "token",
|
||||||
user: mockUser,
|
user: mockUser,
|
||||||
|
});
|
||||||
|
renderGuard(
|
||||||
|
<ProtectedRoute>
|
||||||
|
<div>Secret</div>
|
||||||
|
</ProtectedRoute>,
|
||||||
|
"/protected",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText("Secret")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
renderGuard(
|
|
||||||
<ProtectedRoute>
|
|
||||||
<div>Secret</div>
|
|
||||||
</ProtectedRoute>,
|
|
||||||
"/protected",
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(screen.getByText("Secret")).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("PublicRoute", () => {
|
describe("PublicRoute", () => {
|
||||||
it("should show SplashScreen while auth is initializing", () => {
|
it("should show SplashScreen while auth is initializing", () => {
|
||||||
useAuthStore.setState({
|
useAuthStore.setState({
|
||||||
isInitializing: true,
|
isInitializing: true,
|
||||||
accessToken: null,
|
accessToken: null,
|
||||||
user: null,
|
user: null,
|
||||||
|
});
|
||||||
|
renderGuard(
|
||||||
|
<AutoRedirectRoute>
|
||||||
|
<div>Login Page</div>
|
||||||
|
</AutoRedirectRoute>,
|
||||||
|
"/public",
|
||||||
|
);
|
||||||
|
expect(screen.getByText(/Unsealing/i)).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText("Login Page")).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
renderGuard(
|
|
||||||
<PublicRoute>
|
|
||||||
<div>Login Page</div>
|
|
||||||
</PublicRoute>,
|
|
||||||
"/public",
|
|
||||||
);
|
|
||||||
expect(screen.getByText(/Unsealing/i)).toBeInTheDocument();
|
|
||||||
expect(screen.queryByText("Login Page")).not.toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should redirect authenticated users to /drawer", () => {
|
it("should redirect authenticated users to /drawer", () => {
|
||||||
useAuthStore.setState({
|
useAuthStore.setState({
|
||||||
isInitializing: false,
|
isInitializing: false,
|
||||||
accessToken: "token",
|
accessToken: "token",
|
||||||
user: mockUser,
|
user: mockUser,
|
||||||
|
});
|
||||||
|
renderGuard(
|
||||||
|
<AutoRedirectRoute>
|
||||||
|
<div>Login Form</div>
|
||||||
|
</AutoRedirectRoute>,
|
||||||
|
"/public",
|
||||||
|
);
|
||||||
|
expect(screen.getByText("Drawer Page")).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText("Login Form")).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
renderGuard(
|
|
||||||
<PublicRoute>
|
|
||||||
<div>Login Form</div>
|
|
||||||
</PublicRoute>,
|
|
||||||
"/public",
|
|
||||||
);
|
|
||||||
expect(screen.getByText("Drawer Page")).toBeInTheDocument();
|
|
||||||
expect(screen.queryByText("Login Form")).not.toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render page for unauthenticated users", () => {
|
it("should render page for unauthenticated users", () => {
|
||||||
useAuthStore.setState({
|
useAuthStore.setState({
|
||||||
isInitializing: false,
|
isInitializing: false,
|
||||||
accessToken: null,
|
accessToken: null,
|
||||||
user: null,
|
user: null,
|
||||||
|
});
|
||||||
|
renderGuard(
|
||||||
|
<AutoRedirectRoute>
|
||||||
|
<div>Login Form</div>
|
||||||
|
</AutoRedirectRoute>,
|
||||||
|
"/public",
|
||||||
|
);
|
||||||
|
expect(screen.getByText("Login Form")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
renderGuard(
|
|
||||||
<PublicRoute>
|
|
||||||
<div>Login Form</div>
|
|
||||||
</PublicRoute>,
|
|
||||||
"/public",
|
|
||||||
);
|
|
||||||
expect(screen.getByText("Login Form")).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,30 +9,30 @@ import SplashScreen from "./SplashScreen";
|
|||||||
* state so the Login component can link them back after sign-in
|
* state so the Login component can link them back after sign-in
|
||||||
*/
|
*/
|
||||||
export function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
export function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
||||||
const { isAuthenticated, isInitializing } = useAuth();
|
const { isAuthenticated, isInitializing } = useAuth();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
if (isInitializing) return <SplashScreen />;
|
if (isInitializing) return <SplashScreen />;
|
||||||
|
|
||||||
if (!isAuthenticated) {
|
if (!isAuthenticated) {
|
||||||
return <Navigate to={ROUTES.LOGIN} state={{ from: location }} replace />;
|
return <Navigate to={ROUTES.LOGIN} state={{ from: location }} replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public - auth route guard.
|
* Auto-redirect - auth route guard.
|
||||||
* If authenticated, redirect all the auth related flows to the drawer
|
* If authenticated, redirect all the auth related flows to the drawer
|
||||||
*/
|
*/
|
||||||
export function PublicRoute({ children }: { children: React.ReactNode }) {
|
export function AutoRedirectRoute({ children }: { children: React.ReactNode }) {
|
||||||
const { isAuthenticated, isInitializing } = useAuth();
|
const { isAuthenticated, isInitializing } = useAuth();
|
||||||
|
|
||||||
if (isInitializing) return <SplashScreen />;
|
if (isInitializing) return <SplashScreen />;
|
||||||
|
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
return <Navigate to={ROUTES.DRAWER} replace />;
|
return <Navigate to={ROUTES.DRAWER} replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user