1
0
forked from baron/baron-sso
Files
baron-sso/devfront/src/features/clients/routes/ClientFederationPage.test.tsx

180 lines
5.3 KiB
TypeScript

import { act } from "react-dom/test-utils";
import { createRoot, type Root } from "react-dom/client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { ClientFederationPage } from "./ClientFederationPage";
let params: { id?: string } = { id: "client-a" };
const listIdpConfigsMock = vi.fn();
const createIdpConfigMock = vi.fn();
vi.mock("react-router-dom", async () => {
const actual =
await vi.importActual<typeof import("react-router-dom")>(
"react-router-dom",
);
return {
...actual,
useParams: () => params,
};
});
vi.mock("../../../lib/devApi", () => ({
listIdpConfigsForClient: (clientId: string) => listIdpConfigsMock(clientId),
createIdpConfigForClient: (payload: unknown) => createIdpConfigMock(payload),
}));
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 roots: Root[] = [];
afterEach(() => {
for (const root of roots.splice(0)) {
act(() => {
root.unmount();
});
}
vi.clearAllMocks();
document.body.innerHTML = "";
});
beforeEach(() => {
params = { id: "client-a" };
listIdpConfigsMock.mockResolvedValue([
{
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",
},
]);
createIdpConfigMock.mockResolvedValue({
id: "idp-2",
client_id: "client-a",
provider_type: "oidc",
display_name: "New Provider",
status: "active",
createdAt: "2026-05-02T00:00:00Z",
updatedAt: "2026-05-02T00:00:00Z",
});
});
async function setInputValue(input: HTMLInputElement, value: string) {
const descriptor = Object.getOwnPropertyDescriptor(
HTMLInputElement.prototype,
"value",
);
descriptor?.set?.call(input, value);
input.dispatchEvent(new Event("input", { bubbles: true }));
await new Promise((resolve) => setTimeout(resolve, 0));
}
async function renderPage() {
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}>
<ClientFederationPage />
</QueryClientProvider>,
);
});
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
return container;
}
describe("ClientFederationPage", () => {
it("shows a missing client id message when no route param exists", async () => {
params = {};
const container = await renderPage();
expect(container.textContent).toContain("Client ID is missing");
});
it("opens the create modal and submits a new IdP config", async () => {
const container = await renderPage();
expect(container.textContent).toContain("Workspace OIDC");
const addButton = Array.from(container.querySelectorAll("button")).find(
(button) => button.textContent === "Add Provider",
);
expect(addButton).toBeTruthy();
await act(async () => {
addButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
});
expect(container.textContent).toContain("Add Identity Provider");
const displayName = container.querySelector(
'input[name="display_name"]',
) as HTMLInputElement | null;
const issuerUrl = container.querySelector(
'input[name="issuer_url"]',
) as HTMLInputElement | null;
const clientId = container.querySelector(
'input[name="oidc_client_id"]',
) as HTMLInputElement | null;
const clientSecret = container.querySelector(
'input[name="oidc_client_secret"]',
) as HTMLInputElement | null;
if (!displayName || !issuerUrl || !clientId || !clientSecret) {
throw new Error("Expected federation form inputs to be rendered");
}
await act(async () => {
await setInputValue(displayName, "New Provider");
await setInputValue(issuerUrl, "https://login.example");
await setInputValue(clientId, "client-oidc");
await setInputValue(clientSecret, "secret-value");
});
const submitButton = Array.from(container.querySelectorAll("button")).find(
(button) => button.textContent === "Save Configuration",
);
expect(submitButton).toBeTruthy();
await act(async () => {
submitButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
await new Promise((resolve) => setTimeout(resolve, 0));
});
expect(createIdpConfigMock).toHaveBeenCalledWith(
expect.objectContaining({
client_id: "client-a",
display_name: "New Provider",
issuer_url: "https://login.example",
oidc_client_id: "client-oidc",
oidc_client_secret: "secret-value",
}),
);
});
});