101 lines
3.2 KiB
JavaScript
101 lines
3.2 KiB
JavaScript
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 }) => (
|
||
<div data-can-credit={String(can("lucky-gift:pool-credit"))} data-testid="ops-center-app" />
|
||
),
|
||
}));
|
||
|
||
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(
|
||
<AuthProvider>
|
||
<AuthenticatedOpsCenter targetWindow={targetWindow} />
|
||
</AuthProvider>,
|
||
);
|
||
|
||
// 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(
|
||
<AuthProvider>
|
||
<AuthenticatedOpsCenter targetWindow={targetWindow} />
|
||
</AuthProvider>,
|
||
);
|
||
|
||
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 };
|
||
}
|