1
0
forked from baron/baron-sso

test: raise frontend coverage baselines

This commit is contained in:
2026-05-29 14:31:10 +09:00
parent 592c1d1741
commit 3e31fdfa0c
50 changed files with 3482 additions and 214 deletions

View File

@@ -1,23 +1,161 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
const apiClient = {
get: vi.fn(),
post: vi.fn(),
put: vi.fn(),
delete: vi.fn(),
};
const fetchAllCursorPages = vi.fn(async () => ({
items: [{ id: "tenant-1", name: "Tenant", slug: "tenant" }],
total: 1,
}));
vi.mock("./apiClient", () => ({
default: apiClient,
}));
vi.mock("./auth", () => ({
userManager: {
getUser: vi.fn(async () => ({ access_token: "access-token" })),
},
}));
vi.mock("../../../common/core/pagination", () => ({
fetchAllCursorPages,
}));
describe("orgfront adminApi user tenant payloads", () => {
beforeEach(() => {
apiClient.get.mockReset();
apiClient.post.mockReset();
apiClient.put.mockReset();
apiClient.delete.mockReset();
apiClient.get.mockResolvedValue({ data: { ok: true } });
apiClient.post.mockResolvedValue({ data: { ok: true } });
apiClient.put.mockResolvedValue({ data: { ok: true } });
apiClient.delete.mockResolvedValue({ data: { ok: true } });
fetchAllCursorPages.mockClear();
window.localStorage.clear();
});
it("routes read APIs to their documented orgfront admin endpoints", async () => {
const adminApi = await import("./adminApi");
await adminApi.fetchAuditLogs(10, "cursor-a");
await adminApi.fetchTenants(25, 50, "parent-1", "cursor-b");
await adminApi.fetchAllTenants({ pageSize: 200, parentId: "parent-1" });
await adminApi.fetchTenant("tenant-1");
await adminApi.fetchTenantAdmins("tenant-1");
await adminApi.fetchTenantOwners("tenant-1");
await adminApi.fetchGroups("tenant-1");
await adminApi.fetchGroup("tenant-1", "group-1");
await adminApi.fetchImportProgress("tenant-1", "progress-1");
await adminApi.fetchGroupRoles("tenant-1", "group-1");
await adminApi.fetchApiKeys(20, 40);
await adminApi.fetchUsers(30, 60, "admin", "tenant");
await adminApi.fetchUser("user-1");
await adminApi.fetchPasswordPolicy();
await adminApi.fetchUserRpHistory("user-1");
await adminApi.fetchMe();
await adminApi.fetchRelyingParties("tenant-1");
await adminApi.fetchAllRelyingParties();
await adminApi.fetchRelyingParty("client-1");
await adminApi.fetchRPOwners("client-1");
await adminApi.fetchPublicOrgChart("public-token");
expect(apiClient.get).toHaveBeenCalledWith("/v1/audit", {
params: { limit: 10, cursor: "cursor-a" },
});
expect(apiClient.get).toHaveBeenCalledWith("/v1/admin/tenants", {
params: {
limit: 25,
offset: 50,
parentId: "parent-1",
cursor: "cursor-b",
},
});
expect(fetchAllCursorPages).toHaveBeenCalledWith(
expect.objectContaining({
path: "/v1/admin/tenants",
pageSize: 200,
params: { parentId: "parent-1" },
}),
);
expect(apiClient.get).toHaveBeenCalledWith(
"/v1/admin/tenants/tenant-1/organization/group-1/roles",
);
expect(apiClient.get).toHaveBeenCalledWith("/v1/public/orgchart", {
params: { token: "public-token" },
});
});
it("routes mutation APIs to their documented orgfront admin endpoints", async () => {
const adminApi = await import("./adminApi");
await adminApi.createTenant({ name: "Tenant", slug: "tenant" });
await adminApi.updateTenant("tenant-1", { status: "inactive" });
await adminApi.deleteTenant("tenant-1");
await adminApi.deleteTenantsBulk(["tenant-1"]);
await adminApi.approveTenant("tenant-1");
await adminApi.addTenantAdmin("tenant-1", "user-1");
await adminApi.removeTenantAdmin("tenant-1", "user-1");
await adminApi.addTenantOwner("tenant-1", "user-1");
await adminApi.removeTenantOwner("tenant-1", "user-1");
await adminApi.createGroup("tenant-1", { name: "Group" });
await adminApi.deleteGroup("tenant-1", "group-1");
await adminApi.addGroupMember("tenant-1", "group-1", "user-1");
await adminApi.removeGroupMember("tenant-1", "group-1", "user-1");
await adminApi.importOrgChart(
"tenant-1",
new File(["name"], "org.csv"),
"progress-1",
);
await adminApi.assignGroupRole("tenant-1", "group-1", "tenant-2", "owner");
await adminApi.removeGroupRole("tenant-1", "group-1", "tenant-2", "owner");
await adminApi.createApiKey({ name: "key", scopes: ["read"] });
await adminApi.deleteApiKey("key-1");
await adminApi.createUser({ email: "user@example.com", name: "User" });
await adminApi.bulkCreateUsers([
{ email: "user@example.com", name: "User", metadata: {} },
]);
await adminApi.bulkUpdateUsers({ userIds: ["user-1"], status: "inactive" });
await adminApi.bulkDeleteUsers(["user-1"]);
await adminApi.updateUser("user-1", { status: "active" });
await adminApi.deleteUser("user-1");
await adminApi.createRelyingParty("tenant-1", {
client_name: "RP",
redirect_uris: ["https://rp.example/callback"],
});
await adminApi.updateRelyingParty("client-1", {
client_name: "RP",
redirect_uris: ["https://rp.example/callback"],
});
await adminApi.deleteRelyingParty("client-1");
await adminApi.addRPOwner("client-1", "User:user-1");
await adminApi.removeRPOwner("client-1", "User:user-1");
expect(apiClient.post).toHaveBeenCalledWith(
"/v1/admin/tenants/tenant-1/organization/group-1/members",
{ userId: "user-1" },
);
expect(apiClient.post).toHaveBeenCalledWith(
"/v1/admin/tenants/tenant-1/organization/import?progressId=progress-1",
expect.any(FormData),
{ headers: { "Content-Type": "multipart/form-data" } },
);
expect(apiClient.put).toHaveBeenCalledWith("/v1/admin/users/user-1", {
status: "active",
});
expect(apiClient.delete).toHaveBeenCalledWith(
"/v1/admin/relying-parties/client-1/owners/User:user-1",
);
});
it("sends tenantSlug without remapping it to companyCode when creating a user", async () => {
const { createUser } = await import("./adminApi");
apiClient.post.mockResolvedValue({ data: {} });
await createUser({
email: "user@test.com",
@@ -34,7 +172,6 @@ describe("orgfront adminApi user tenant payloads", () => {
it("sends tenantSlug without remapping it to companyCode when updating a user", async () => {
const { updateUser } = await import("./adminApi");
apiClient.put.mockResolvedValue({ data: {} });
await updateUser("user-id", { tenantSlug: "new-tenant" });
@@ -47,8 +184,6 @@ describe("orgfront adminApi user tenant payloads", () => {
it("keeps tenantSlug payloads unchanged for bulk user APIs", async () => {
const { bulkCreateUsers, bulkUpdateUsers } = await import("./adminApi");
apiClient.post.mockResolvedValue({ data: {} });
apiClient.put.mockResolvedValue({ data: {} });
await bulkCreateUsers([
{

View File

@@ -0,0 +1,139 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
const apiClient = {
get: vi.fn(),
post: vi.fn(),
put: vi.fn(),
patch: vi.fn(),
delete: vi.fn(),
};
vi.mock("./apiClient", () => ({
default: apiClient,
}));
describe("orgfront devApi", () => {
beforeEach(() => {
apiClient.get.mockReset();
apiClient.post.mockReset();
apiClient.put.mockReset();
apiClient.patch.mockReset();
apiClient.delete.mockReset();
apiClient.get.mockResolvedValue({ data: { ok: true } });
apiClient.post.mockResolvedValue({ data: { ok: true } });
apiClient.put.mockResolvedValue({ data: { ok: true } });
apiClient.patch.mockResolvedValue({ data: { ok: true } });
apiClient.delete.mockResolvedValue({ data: { ok: true } });
});
it("fetches dev resources with expected query parameters", async () => {
const {
fetchClients,
fetchDevStats,
fetchClient,
fetchConsents,
fetchDevAuditLogs,
fetchMyTenants,
listIdpConfigsForClient,
} = await import("./devApi");
await fetchClients();
await fetchDevStats();
await fetchClient("client-a");
await fetchConsents("user-a", "client-a", "active");
await fetchDevAuditLogs(10, "cursor-a", {
action: "client.update",
client_id: "client-a",
status: "success",
tenant_id: "tenant-a",
});
await fetchMyTenants();
await listIdpConfigsForClient("client-a");
expect(apiClient.get).toHaveBeenCalledWith("/dev/clients");
expect(apiClient.get).toHaveBeenCalledWith("/dev/stats");
expect(apiClient.get).toHaveBeenCalledWith("/dev/clients/client-a");
expect(apiClient.get).toHaveBeenCalledWith("/dev/consents", {
params: { subject: "user-a", client_id: "client-a", status: "active" },
});
expect(apiClient.get).toHaveBeenCalledWith("/dev/audit-logs", {
params: {
limit: 10,
cursor: "cursor-a",
action: "client.update",
client_id: "client-a",
status: "success",
tenant_id: "tenant-a",
},
});
expect(apiClient.get).toHaveBeenCalledWith("/dev/my-tenants");
expect(apiClient.get).toHaveBeenCalledWith("/dev/clients/client-a/idps");
});
it("omits optional consent filters when they are empty or all", async () => {
const { fetchConsents, revokeConsent } = await import("./devApi");
await fetchConsents("user-a", undefined, "all");
await revokeConsent("user-a");
expect(apiClient.get).toHaveBeenCalledWith("/dev/consents", {
params: { subject: "user-a" },
});
expect(apiClient.delete).toHaveBeenCalledWith("/dev/consents", {
params: { subject: "user-a" },
});
});
it("sends mutation requests to the documented dev endpoints", async () => {
const {
updateClientStatus,
createClient,
updateClient,
rotateClientSecret,
refreshHeadlessJwksCache,
revokeHeadlessJwksCache,
deleteClient,
revokeConsent,
createIdpConfigForClient,
updateIdpConfig,
deleteIdpConfig,
} = await import("./devApi");
await updateClientStatus("client-a", "inactive");
await createClient({ id: "client-a", name: "Console App" });
await updateClient("client-a", { name: "Console App Updated" });
await rotateClientSecret("client-a");
await refreshHeadlessJwksCache("client-a");
await revokeHeadlessJwksCache("client-a");
await deleteClient("client-a");
await revokeConsent("user-a", "client-a");
await createIdpConfigForClient({
client_id: "client-a",
provider_type: "oidc",
display_name: "OIDC Provider",
status: "active",
});
await updateIdpConfig("client-a", "idp-a", { status: "inactive" });
await deleteIdpConfig("client-a", "idp-a");
expect(apiClient.patch).toHaveBeenCalledWith(
"/dev/clients/client-a/status",
{ status: "inactive" },
);
expect(apiClient.post).toHaveBeenCalledWith("/dev/clients", {
id: "client-a",
name: "Console App",
});
expect(apiClient.put).toHaveBeenCalledWith("/dev/clients/client-a", {
name: "Console App Updated",
});
expect(apiClient.delete).toHaveBeenCalledWith("/dev/consents", {
params: { subject: "user-a", client_id: "client-a" },
});
expect(apiClient.put).toHaveBeenCalledWith(
"/dev/clients/client-a/idps/idp-a",
{ status: "inactive" },
);
});
});