forked from baron/baron-sso
test: raise frontend coverage baselines
This commit is contained in:
307
orgfront/src/features/coverage/pageSmoke.test.tsx
Normal file
307
orgfront/src/features/coverage/pageSmoke.test.tsx
Normal file
@@ -0,0 +1,307 @@
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { act } from "react";
|
||||
import { createRoot, type Root } from "react-dom/client";
|
||||
import { MemoryRouter, Route, Routes } from "react-router-dom";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { ForbiddenMessage } from "../../components/common/ForbiddenMessage";
|
||||
import AuditLogsPage from "../audit/AuditLogsPage";
|
||||
import AuthPage from "../auth/AuthPage";
|
||||
import ClientConsentsPage from "../clients/ClientConsentsPage";
|
||||
import ClientDetailsPage from "../clients/ClientDetailsPage";
|
||||
import ClientGeneralPage from "../clients/ClientGeneralPage";
|
||||
import ClientsPage from "../clients/ClientsPage";
|
||||
import { ClientFederationPage } from "../clients/routes/ClientFederationPage";
|
||||
import DashboardPage from "../dashboard/DashboardPage";
|
||||
import ProfilePage from "../profile/ProfilePage";
|
||||
|
||||
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
vi.mock("react-oidc-context", () => ({
|
||||
useAuth: () => ({
|
||||
isAuthenticated: true,
|
||||
isLoading: false,
|
||||
user: {
|
||||
access_token: "access-token",
|
||||
profile: {
|
||||
sub: "user-1",
|
||||
role: "super_admin",
|
||||
tenant_id: "tenant-1",
|
||||
},
|
||||
},
|
||||
signinRedirect: vi.fn(),
|
||||
removeUser: vi.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("../../lib/i18n", () => ({
|
||||
t: (key: string, fallback?: string, vars?: Record<string, unknown>) => {
|
||||
let text = fallback ?? key;
|
||||
for (const [name, value] of Object.entries(vars ?? {})) {
|
||||
text = text.replaceAll(`{{${name}}}`, String(value));
|
||||
}
|
||||
return text;
|
||||
},
|
||||
}));
|
||||
|
||||
const clientSummary = {
|
||||
id: "client-a",
|
||||
name: "Console App",
|
||||
type: "private" as const,
|
||||
status: "active" as const,
|
||||
createdAt: "2026-05-01T00:00:00Z",
|
||||
redirectUris: ["https://app.example/callback"],
|
||||
scopes: ["openid", "profile"],
|
||||
tokenEndpointAuthMethod: "client_secret_basic",
|
||||
metadata: {
|
||||
headless_login_enabled: true,
|
||||
headless_login_jwks_uri: "https://app.example/jwks.json",
|
||||
},
|
||||
};
|
||||
|
||||
const clientDetail = {
|
||||
client: {
|
||||
...clientSummary,
|
||||
clientSecret: "secret-value",
|
||||
jwksUri: "https://app.example/jwks.json",
|
||||
grantTypes: ["authorization_code"],
|
||||
responseTypes: ["code"],
|
||||
},
|
||||
endpoints: {
|
||||
discovery: "https://sso.example/.well-known/openid-configuration",
|
||||
issuer: "https://sso.example",
|
||||
authorization: "https://sso.example/oauth2/auth",
|
||||
token: "https://sso.example/oauth2/token",
|
||||
userinfo: "https://sso.example/userinfo",
|
||||
},
|
||||
headlessJwksCache: {
|
||||
clientId: "client-a",
|
||||
jwksUri: "https://app.example/jwks.json",
|
||||
cachedAt: "2026-05-01T00:00:00Z",
|
||||
expiresAt: "2026-05-02T00:00:00Z",
|
||||
lastRefreshStatus: "success" as const,
|
||||
cachedKids: ["kid-1"],
|
||||
parsedKeys: [{ kid: "kid-1", kty: "RSA", use: "sig", alg: "RS256" }],
|
||||
},
|
||||
};
|
||||
|
||||
vi.mock("../../lib/devApi", () => ({
|
||||
fetchClients: vi.fn(async () => ({
|
||||
items: [clientSummary],
|
||||
limit: 100,
|
||||
offset: 0,
|
||||
})),
|
||||
fetchDevStats: vi.fn(async () => ({
|
||||
total_clients: 1,
|
||||
active_sessions: 12,
|
||||
auth_failures_24h: 2,
|
||||
})),
|
||||
fetchClient: vi.fn(async () => clientDetail),
|
||||
updateClientStatus: vi.fn(async () => clientDetail),
|
||||
createClient: vi.fn(async () => clientDetail),
|
||||
updateClient: vi.fn(async () => clientDetail),
|
||||
rotateClientSecret: vi.fn(async () => clientDetail),
|
||||
refreshHeadlessJwksCache: vi.fn(async () => clientDetail),
|
||||
revokeHeadlessJwksCache: vi.fn(async () => undefined),
|
||||
deleteClient: vi.fn(async () => undefined),
|
||||
fetchConsents: vi.fn(async () => ({
|
||||
items: [
|
||||
{
|
||||
subject: "user-1",
|
||||
userName: "Consent User",
|
||||
clientId: "client-a",
|
||||
clientName: "Console App",
|
||||
grantedScopes: ["openid", "profile"],
|
||||
authenticatedAt: "2026-05-01T02:00:00Z",
|
||||
createdAt: "2026-05-01T00:00:00Z",
|
||||
status: "active",
|
||||
tenantId: "tenant-1",
|
||||
tenantName: "Hanmac",
|
||||
},
|
||||
],
|
||||
})),
|
||||
revokeConsent: vi.fn(async () => undefined),
|
||||
listIdpConfigsForClient: vi.fn(async () => [
|
||||
{
|
||||
id: "idp-1",
|
||||
client_id: "client-a",
|
||||
provider_type: "oidc",
|
||||
display_name: "Workspace OIDC",
|
||||
status: "active",
|
||||
issuer_url: "https://accounts.example",
|
||||
oidc_client_id: "oidc-client",
|
||||
scopes: "openid email profile",
|
||||
createdAt: "2026-05-01T00:00:00Z",
|
||||
updatedAt: "2026-05-01T00:00:00Z",
|
||||
},
|
||||
]),
|
||||
createIdpConfigForClient: vi.fn(async (payload) => ({
|
||||
id: "idp-1",
|
||||
...payload,
|
||||
status: "active",
|
||||
createdAt: "2026-05-01T00:00:00Z",
|
||||
updatedAt: "2026-05-01T00:00:00Z",
|
||||
})),
|
||||
updateIdpConfig: vi.fn(async (_clientId, idpId, payload) => ({
|
||||
id: idpId,
|
||||
client_id: "client-a",
|
||||
provider_type: "oidc",
|
||||
display_name: "Provider",
|
||||
status: "active",
|
||||
createdAt: "2026-05-01T00:00:00Z",
|
||||
updatedAt: "2026-05-01T00:00:00Z",
|
||||
...payload,
|
||||
})),
|
||||
deleteIdpConfig: vi.fn(async () => undefined),
|
||||
fetchDevAuditLogs: vi.fn(async () => ({
|
||||
items: [
|
||||
{
|
||||
event_id: "event-1",
|
||||
timestamp: "2026-05-01T00:00:00Z",
|
||||
user_id: "user-1",
|
||||
event_type: "client.update",
|
||||
status: "success",
|
||||
ip_address: "127.0.0.1",
|
||||
user_agent: "vitest",
|
||||
details: JSON.stringify({
|
||||
action: "client.update",
|
||||
target_id: "client-a",
|
||||
tenant_id: "tenant-1",
|
||||
request_id: "req-1",
|
||||
}),
|
||||
},
|
||||
],
|
||||
limit: 50,
|
||||
})),
|
||||
fetchMyTenants: vi.fn(async () => [
|
||||
{ id: "tenant-1", name: "Hanmac", slug: "hanmac" },
|
||||
]),
|
||||
}));
|
||||
|
||||
vi.mock("../auth/authApi", () => ({
|
||||
fetchMe: vi.fn(async () => ({
|
||||
id: "user-1",
|
||||
name: "Org User",
|
||||
email: "org@example.com",
|
||||
phone: "010-0000-0000",
|
||||
role: "super_admin",
|
||||
department: "Platform",
|
||||
tenantId: "tenant-1",
|
||||
tenant: { id: "tenant-1", name: "Hanmac", slug: "hanmac" },
|
||||
})),
|
||||
}));
|
||||
|
||||
const roots: Root[] = [];
|
||||
|
||||
afterEach(() => {
|
||||
for (const root of roots.splice(0)) {
|
||||
act(() => {
|
||||
root.unmount();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
async function renderWithProviders(
|
||||
element: React.ReactElement,
|
||||
initialEntry = "/",
|
||||
) {
|
||||
const container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
const root = createRoot(container);
|
||||
roots.push(root);
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: { retry: false },
|
||||
mutations: { retry: false },
|
||||
},
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
root.render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<MemoryRouter initialEntries={[initialEntry]}>{element}</MemoryRouter>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
});
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
describe("orgfront page smoke coverage", () => {
|
||||
it("renders the dashboard content", async () => {
|
||||
const container = await renderWithProviders(<DashboardPage />);
|
||||
|
||||
expect(container.textContent).toContain("RP 등록 현황");
|
||||
expect(container.textContent).toContain("Stack readiness");
|
||||
});
|
||||
|
||||
it("renders static auth guidance and forbidden messages", async () => {
|
||||
const auth = await renderWithProviders(<AuthPage />);
|
||||
expect(auth.textContent).toContain("Admin auth guardrails");
|
||||
expect(auth.textContent).toContain("TTL discipline");
|
||||
|
||||
const forbidden = await renderWithProviders(
|
||||
<ForbiddenMessage resourceToken="clients" />,
|
||||
);
|
||||
expect(forbidden.textContent).toContain("연동 앱 접근 권한 없음");
|
||||
});
|
||||
|
||||
it("renders client list, detail, edit, consent, and federation pages", async () => {
|
||||
const clients = await renderWithProviders(
|
||||
<Routes>
|
||||
<Route path="/clients" element={<ClientsPage />} />
|
||||
</Routes>,
|
||||
"/clients",
|
||||
);
|
||||
expect(clients.textContent).toContain("Console App");
|
||||
|
||||
const details = await renderWithProviders(
|
||||
<Routes>
|
||||
<Route path="/clients/:id" element={<ClientDetailsPage />} />
|
||||
</Routes>,
|
||||
"/clients/client-a",
|
||||
);
|
||||
expect(details.textContent).toContain("Client Secret");
|
||||
expect(details.textContent).toContain("https://sso.example/oauth2/token");
|
||||
|
||||
const general = await renderWithProviders(
|
||||
<Routes>
|
||||
<Route path="/clients/:id/edit" element={<ClientGeneralPage />} />
|
||||
</Routes>,
|
||||
"/clients/client-a/edit",
|
||||
);
|
||||
expect(general.textContent).toContain("Console App");
|
||||
|
||||
const consents = await renderWithProviders(
|
||||
<Routes>
|
||||
<Route path="/clients/:id/consents" element={<ClientConsentsPage />} />
|
||||
</Routes>,
|
||||
"/clients/client-a/consents",
|
||||
);
|
||||
expect(consents.textContent).toContain("Consent User");
|
||||
|
||||
const federation = await renderWithProviders(
|
||||
<Routes>
|
||||
<Route
|
||||
path="/clients/:id/federation"
|
||||
element={<ClientFederationPage />}
|
||||
/>
|
||||
</Routes>,
|
||||
"/clients/client-a/federation",
|
||||
);
|
||||
expect(federation.textContent).toContain("Workspace OIDC");
|
||||
});
|
||||
|
||||
it("renders audit logs and profile pages", async () => {
|
||||
const auditLogs = await renderWithProviders(<AuditLogsPage />);
|
||||
expect(auditLogs.textContent).toContain("client.update");
|
||||
expect(auditLogs.textContent).toContain("Loaded 1 rows");
|
||||
|
||||
const profile = await renderWithProviders(<ProfilePage />);
|
||||
expect(profile.textContent).toContain("Org User");
|
||||
expect(profile.textContent).toContain("Hanmac");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user