83 lines
3.1 KiB
TypeScript
83 lines
3.1 KiB
TypeScript
import { render, screen, waitFor } from "@testing-library/react";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const { checkKillSwitchMock, logoutMock, refreshStoredAuthSessionMock, replaceMock, useAuthMock } = vi.hoisted(() => ({
|
|
checkKillSwitchMock: vi.fn(async () => ({ disabled: false, message: "" })),
|
|
logoutMock: vi.fn(),
|
|
refreshStoredAuthSessionMock: vi.fn(async () => true),
|
|
replaceMock: vi.fn(),
|
|
useAuthMock: vi.fn(() => ({ isAuthenticated: true, isLoading: false, logout: logoutMock })),
|
|
}));
|
|
|
|
vi.mock("next/navigation", () => ({
|
|
useRouter: () => ({ replace: replaceMock }),
|
|
}));
|
|
|
|
vi.mock("@/lib/auth", () => ({
|
|
useAuth: useAuthMock,
|
|
}));
|
|
|
|
vi.mock("@/lib/auth-session", () => ({
|
|
refreshStoredAuthSession: refreshStoredAuthSessionMock,
|
|
}));
|
|
|
|
vi.mock("@/lib/kill-switch", () => ({
|
|
checkKillSwitch: checkKillSwitchMock,
|
|
}));
|
|
|
|
import { AuthGuard } from "./AuthGuard";
|
|
|
|
describe("AuthGuard", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
useAuthMock.mockReturnValue({ isAuthenticated: true, isLoading: false, logout: logoutMock });
|
|
refreshStoredAuthSessionMock.mockResolvedValue(true);
|
|
checkKillSwitchMock.mockResolvedValue({ disabled: false, message: "" });
|
|
});
|
|
|
|
it("redirects unauthenticated users to login", async () => {
|
|
useAuthMock.mockReturnValue({ isAuthenticated: false, isLoading: false, logout: logoutMock });
|
|
|
|
render(<AuthGuard><div>Private app</div></AuthGuard>);
|
|
|
|
await waitFor(() => expect(replaceMock).toHaveBeenCalledWith("/login"));
|
|
expect(screen.queryByText("Private app")).not.toBeInTheDocument();
|
|
});
|
|
|
|
it("refreshes an expired stored session before showing protected content", async () => {
|
|
render(<AuthGuard><div>Private app</div></AuthGuard>);
|
|
|
|
await waitFor(() => expect(refreshStoredAuthSessionMock).toHaveBeenCalledOnce());
|
|
expect(await screen.findByText("Private app")).toBeInTheDocument();
|
|
expect(logoutMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("logs out and redirects when session refresh fails", async () => {
|
|
refreshStoredAuthSessionMock.mockResolvedValue(false);
|
|
|
|
render(<AuthGuard><div>Private app</div></AuthGuard>);
|
|
|
|
await waitFor(() => expect(logoutMock).toHaveBeenCalledOnce());
|
|
expect(replaceMock).toHaveBeenCalledWith("/login");
|
|
expect(screen.queryByText("Private app")).not.toBeInTheDocument();
|
|
});
|
|
|
|
it("keeps protected content hidden when the kill switch is active", async () => {
|
|
checkKillSwitchMock.mockResolvedValue({ disabled: true, message: "Maintenance window" });
|
|
|
|
render(<AuthGuard><div>Private app</div></AuthGuard>);
|
|
|
|
expect(await screen.findByText("Maintenance window")).toBeInTheDocument();
|
|
expect(screen.queryByText("Private app")).not.toBeInTheDocument();
|
|
});
|
|
|
|
it("shows a platform-down state when readiness cannot be checked", async () => {
|
|
checkKillSwitchMock.mockRejectedValue(new Error("HTTP 503 Service Unavailable"));
|
|
|
|
render(<AuthGuard><div>Private app</div></AuthGuard>);
|
|
|
|
expect(await screen.findByText("Platform services are unavailable")).toBeInTheDocument();
|
|
expect(screen.queryByText("Private app")).not.toBeInTheDocument();
|
|
});
|
|
});
|