forked from baron/baron-sso
121 lines
3.8 KiB
TypeScript
121 lines
3.8 KiB
TypeScript
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import {
|
|
fetchOrySSOTSystemStatus,
|
|
flushIdentityCache,
|
|
} from "../../lib/adminApi";
|
|
import { createI18nMock } from "../../test/i18nMock";
|
|
import UserProjectionPage from "./UserProjectionPage";
|
|
|
|
vi.mock("../../lib/i18n", () => createI18nMock());
|
|
|
|
let currentRole = "super_admin";
|
|
|
|
vi.mock("../../lib/adminApi", () => ({
|
|
fetchMe: vi.fn(async () => ({ role: currentRole })),
|
|
fetchOrySSOTSystemStatus: vi.fn(async () => ({
|
|
userProjection: {
|
|
name: "kratos_users",
|
|
status: "ready",
|
|
ready: true,
|
|
lastSyncedAt: "2026-05-11T03:00:00Z",
|
|
updatedAt: "2026-05-11T03:00:10Z",
|
|
projectedUsers: 152,
|
|
},
|
|
identityCache: {
|
|
status: "ready",
|
|
redisReady: true,
|
|
observedCount: 151,
|
|
lastRefreshedAt: "2026-05-11T03:00:00Z",
|
|
updatedAt: "2026-05-11T03:00:10Z",
|
|
keyCount: 153,
|
|
},
|
|
})),
|
|
flushIdentityCache: vi.fn(async () => ({
|
|
status: "success",
|
|
flushedKeys: 153,
|
|
updatedAt: "2026-05-11T03:02:00Z",
|
|
})),
|
|
}));
|
|
|
|
function renderPage() {
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: { retry: false },
|
|
mutations: { retry: false },
|
|
},
|
|
});
|
|
|
|
return render(
|
|
<QueryClientProvider client={queryClient}>
|
|
<UserProjectionPage />
|
|
</QueryClientProvider>,
|
|
);
|
|
}
|
|
|
|
describe("UserProjectionPage", () => {
|
|
beforeEach(() => {
|
|
currentRole = "super_admin";
|
|
vi.clearAllMocks();
|
|
vi.spyOn(window, "confirm").mockReturnValue(true);
|
|
window.localStorage.setItem("locale", "ko");
|
|
});
|
|
|
|
it("renders Ory SSOT and Redis identity cache status for super_admin", async () => {
|
|
renderPage();
|
|
|
|
expect(await screen.findByText("Ory SSOT 시스템")).toBeInTheDocument();
|
|
expect(
|
|
await screen.findByText(
|
|
"Kratos 원장과 Redis identity cache 상태를 분리해서 확인합니다.",
|
|
),
|
|
).toBeInTheDocument();
|
|
expect(await screen.findByText("Redis identity cache")).toBeInTheDocument();
|
|
expect(screen.getAllByText("준비됨").length).toBeGreaterThan(0);
|
|
expect(screen.getByText("관측 identity")).toBeInTheDocument();
|
|
expect(screen.getByText("152")).toBeInTheDocument();
|
|
expect(screen.getByText("151")).toBeInTheDocument();
|
|
expect(fetchOrySSOTSystemStatus).toHaveBeenCalled();
|
|
});
|
|
|
|
it("flushes only the Redis identity cache for super_admin", async () => {
|
|
renderPage();
|
|
|
|
await screen.findByText("Ory SSOT 시스템");
|
|
expect(screen.queryByRole("button", { name: /재동기화/ })).toBeNull();
|
|
expect(
|
|
screen.queryByRole("button", { name: /초기화 후 재구축/ }),
|
|
).toBeNull();
|
|
fireEvent.click(screen.getByRole("button", { name: /Redis cache flush/ }));
|
|
|
|
await waitFor(() => {
|
|
expect(flushIdentityCache).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|
|
|
|
it("blocks non-super admins", async () => {
|
|
currentRole = "tenant_admin";
|
|
|
|
renderPage();
|
|
|
|
expect(await screen.findByText("접근 권한이 없습니다")).toBeInTheDocument();
|
|
expect(screen.queryByText("Ory SSOT 시스템")).not.toBeInTheDocument();
|
|
expect(fetchOrySSOTSystemStatus).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("renders localized labels in English", async () => {
|
|
window.localStorage.setItem("locale", "en");
|
|
renderPage();
|
|
|
|
expect(await screen.findByText("Ory SSOT System")).toBeInTheDocument();
|
|
expect(
|
|
await screen.findByText(
|
|
"Review Kratos source-of-truth and Redis identity cache status separately.",
|
|
),
|
|
).toBeInTheDocument();
|
|
expect(screen.getByText("Redis cache flush")).toBeInTheDocument();
|
|
expect((await screen.findAllByText("ready")).length).toBeGreaterThan(0);
|
|
});
|
|
});
|