import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { fireEvent, render, screen, waitFor } from "@testing-library/react"; import type React from "react"; import { MemoryRouter } from "react-router-dom"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { fetchAdminRPUsageDaily, fetchDataIntegrityReport, } from "../../lib/adminApi"; import { createI18nMock } from "../../test/i18nMock"; import AuthPage from "../auth/AuthPage"; import GlobalOverviewPage from "./GlobalOverviewPage"; vi.mock("../../lib/i18n", () => createI18nMock()); let currentRole = "super_admin"; vi.mock("../../lib/adminApi", () => ({ fetchMe: vi.fn(async () => ({ role: currentRole })), fetchAdminOverviewStats: vi.fn(async () => ({ totalTenants: 10, totalUsers: 152, oidcClients: 3, auditEvents24h: 18, })), fetchAllTenants: vi.fn(async () => ({ items: [ { id: "group-1", type: "COMPANY_GROUP", name: "한맥그룹", slug: "hanmac-group", description: "", status: "active", memberCount: 0, createdAt: "2026-05-06T00:00:00Z", updatedAt: "2026-05-06T00:00:00Z", }, { id: "company-1", type: "COMPANY", name: "한맥", slug: "hanmac", description: "", status: "active", memberCount: 0, createdAt: "2026-05-06T00:00:00Z", updatedAt: "2026-05-06T00:00:00Z", }, { id: "org-1", type: "ORGANIZATION", name: "개발팀", slug: "dev-team", description: "", status: "active", memberCount: 0, createdAt: "2026-05-06T00:00:00Z", updatedAt: "2026-05-06T00:00:00Z", }, { id: "personal-1", type: "PERSONAL", name: "개인", slug: "personal", description: "", status: "active", memberCount: 0, createdAt: "2026-05-06T00:00:00Z", updatedAt: "2026-05-06T00:00:00Z", }, ], limit: 1000, offset: 0, total: 4, })), fetchAdminRPUsageDaily: vi.fn(async () => ({ days: 14, period: "day", items: [ { date: "2026-05-05", tenantId: "company-1", tenantType: "COMPANY", tenantName: "한맥", clientId: "orgfront", clientName: "OrgFront", loginRequests: 12, otherRequests: 4, uniqueSubjects: 8, }, { date: "2026-05-06", tenantId: "company-1", tenantType: "COMPANY", tenantName: "한맥", clientId: "adminfront", clientName: "AdminFront", loginRequests: 7, otherRequests: 3, uniqueSubjects: 5, }, { date: "2026-09-28", tenantId: "company-1", tenantType: "COMPANY", tenantName: "한맥", clientId: "devfront", clientName: "DevFront", loginRequests: 2, otherRequests: 1, uniqueSubjects: 2, }, ], })), fetchDataIntegrityReport: vi.fn(async () => ({ status: "fail", checkedAt: "2026-05-14T00:00:00Z", summary: { totalChecks: 5, passed: 4, warnings: 0, failures: 1, }, sections: [ { key: "tenant_integrity", label: "테넌트 정합성", status: "pass", checks: [], }, { key: "user_integrity", label: "사용자 정합성", status: "fail", checks: [], }, ], })), })); function renderWithProviders(ui: React.ReactElement) { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false }, }, }); return render( {ui} , ); } describe("admin overview and auth guard pages", () => { beforeEach(() => { currentRole = "super_admin"; vi.clearAllMocks(); }); it("renders usage trend chart without quick navigation or permission checker", async () => { renderWithProviders(); expect( await screen.findByText("회사별 앱별 로그인 요청 현황"), ).toBeInTheDocument(); expect( await screen.findByLabelText("일 단위 RP 요청 현황"), ).toBeInTheDocument(); expect(await screen.findByText("05.05")).toBeInTheDocument(); expect(await screen.findByText("05.06")).toBeInTheDocument(); expect(screen.queryByText("빠른 작업")).not.toBeInTheDocument(); expect(screen.queryByText("빠른 이동")).not.toBeInTheDocument(); expect(screen.queryByText("테넌트 추가")).not.toBeInTheDocument(); expect(screen.queryByText("ReBAC 권한 검증 도구")).not.toBeInTheDocument(); }); it("renders overview tenant count from the fully fetched tenant list", async () => { renderWithProviders(); expect( (await screen.findByText("전체 테넌트 수")).parentElement, ).toHaveTextContent("4"); expect(screen.getByText("OIDC 클라이언트").parentElement).toHaveTextContent( "3", ); expect(screen.getByText("전체 사용자 수").parentElement).toHaveTextContent( "152", ); expect(screen.getByText("24시간 이벤트").parentElement).toHaveTextContent( "18", ); }); it("limits the overview graph choices to company tenants", async () => { renderWithProviders(); await screen.findByText("회사별 앱별 로그인 요청 현황"); expect( await screen.findByRole("checkbox", { name: "한맥 (hanmac)" }), ).toBeInTheDocument(); expect( screen.queryByText("한맥그룹 (hanmac-group)"), ).not.toBeInTheDocument(); expect(screen.queryByText("개발팀 (dev-team)")).not.toBeInTheDocument(); expect(screen.queryByText("개인 (personal)")).not.toBeInTheDocument(); }); it("changes the RP usage perspective and targets a permitted company", async () => { renderWithProviders(); await screen.findByText("회사별 앱별 로그인 요청 현황"); fireEvent.click(screen.getByRole("button", { name: "주" })); expect(await screen.findAllByText("19(05월1주)")).not.toHaveLength(0); expect(await screen.findAllByText("40(10월1주)")).not.toHaveLength(0); fireEvent.click(screen.getByRole("button", { name: "월" })); fireEvent.click(screen.getByRole("checkbox", { name: "한맥 (hanmac)" })); await waitFor(() => { expect(fetchAdminRPUsageDaily).toHaveBeenLastCalledWith({ days: 90, period: "month", }); }); expect( screen.queryByText("한맥그룹 (hanmac-group)"), ).not.toBeInTheDocument(); expect(screen.queryByText("개발팀 (dev-team)")).not.toBeInTheDocument(); expect(screen.queryByText("개인 (personal)")).not.toBeInTheDocument(); }); it("shows the latest integrity summary at the bottom for super admins only", async () => { renderWithProviders(); expect(await screen.findByText("정합성 최종 검증")).toBeInTheDocument(); expect(screen.getByText("실패 1건")).toBeInTheDocument(); expect(screen.getByText("테넌트 정합성")).toBeInTheDocument(); expect(screen.getByText("사용자 정합성")).toBeInTheDocument(); expect(fetchDataIntegrityReport).toHaveBeenCalledTimes(1); }); it("does not fetch or show the integrity summary for non-super admins", async () => { currentRole = "tenant_admin"; renderWithProviders(); await screen.findByText("회사별 앱별 로그인 요청 현황"); expect(screen.queryByText("정합성 최종 검증")).not.toBeInTheDocument(); expect(fetchDataIntegrityReport).not.toHaveBeenCalled(); }); it("moves the permission checker to the auth guard page and removes mock guardrails", () => { renderWithProviders(); expect(screen.getByText("인증 가드")).toBeInTheDocument(); expect(screen.getByText("ReBAC 권한 검증 도구")).toBeInTheDocument(); expect(screen.queryByText("Admin auth guardrails")).not.toBeInTheDocument(); expect( screen.queryByText("IDP session placeholder"), ).not.toBeInTheDocument(); expect(screen.queryByText("Admin login")).not.toBeInTheDocument(); }); });