import { act, render, screen, waitFor } from "@testing-library/react"; import { beforeEach, expect, test, vi } from "vitest"; import { AuthProvider } from "@/app/auth/AuthProvider.jsx"; import * as authApi from "@/features/auth/api"; import { setAccessToken, setRefreshHandler, setUnauthorizedHandler } from "@/shared/api/request"; import { AuthenticatedOpsCenter } from "./OpsCenterEntry.jsx"; vi.mock("@/features/auth/api", () => ({ getMe: vi.fn(), login: vi.fn(), logout: vi.fn(), refreshSession: vi.fn(), })); vi.mock("./OpsCenterApp.jsx", () => ({ OpsCenterApp: ({ can }) => (
), })); beforeEach(() => { vi.clearAllMocks(); setAccessToken(""); setRefreshHandler(null); setUnauthorizedHandler(null); }); test("does not mount the dashboard without a session and redirects to login with the full ops path", async () => { authApi.refreshSession.mockRejectedValue(new Error("no session")); const targetWindow = fakeWindow("/ops-center/", "?view=configs", "#dynamic_v3"); render( , ); // refresh 尚未结束以及确定无用户后的跳转窗口都只展示骨架,Dashboard 不会发出任何业务请求。 expect(screen.queryByTestId("ops-center-app")).toBeNull(); await waitFor(() => { expect(targetWindow.location.replace).toHaveBeenCalledWith( "/login?redirect=%2Fops-center%2F%3Fview%3Dconfigs%23dynamic_v3", ); }); expect(screen.queryByTestId("ops-center-app")).toBeNull(); }); test("waits for stale-token refresh fallback before mounting the dashboard", async () => { const refresh = deferred(); const me = deferred(); setAccessToken("stale-token"); authApi.refreshSession.mockReturnValue(refresh.promise); authApi.getMe.mockReturnValue(me.promise); const targetWindow = fakeWindow("/ops-center/", "?view=overview", ""); render( , ); expect(screen.queryByTestId("ops-center-app")).toBeNull(); await act(async () => { refresh.reject(new Error("refresh cookie expired")); }); await waitFor(() => expect(authApi.getMe).toHaveBeenCalledTimes(1)); expect(screen.queryByTestId("ops-center-app")).toBeNull(); await act(async () => { me.resolve({ accessToken: "fresh-token", permissions: ["lucky-gift:pool-credit"], user: { id: 1, username: "ops" }, }); }); expect(await screen.findByTestId("ops-center-app")).toHaveAttribute("data-can-credit", "true"); expect(targetWindow.location.replace).not.toHaveBeenCalled(); }); function fakeWindow(pathname, search, hash) { return { location: { hash, pathname, replace: vi.fn(), search, }, }; } function deferred() { let resolve; let reject; const promise = new Promise((resolvePromise, rejectPromise) => { resolve = resolvePromise; reject = rejectPromise; }); return { promise, reject, resolve }; }