forked from baron/baron-sso
217 lines
7.6 KiB
TypeScript
217 lines
7.6 KiB
TypeScript
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");
|
|
await adminApi.fetchOrgChartSnapshot();
|
|
|
|
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" },
|
|
});
|
|
expect(apiClient.get).toHaveBeenCalledWith("/v1/admin/orgchart/snapshot", {
|
|
params: { cache: "redis" },
|
|
});
|
|
});
|
|
|
|
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");
|
|
|
|
await createUser({
|
|
email: "user@test.com",
|
|
name: "Test User",
|
|
tenantSlug: "test-tenant",
|
|
});
|
|
|
|
expect(apiClient.post).toHaveBeenCalledWith(
|
|
"/v1/admin/users",
|
|
expect.objectContaining({ tenantSlug: "test-tenant" }),
|
|
);
|
|
expect(apiClient.post.mock.calls[0][1]).not.toHaveProperty("companyCode");
|
|
});
|
|
|
|
it("sends tenantSlug without remapping it to companyCode when updating a user", async () => {
|
|
const { updateUser } = await import("./adminApi");
|
|
|
|
await updateUser("user-id", { tenantSlug: "new-tenant" });
|
|
|
|
expect(apiClient.put).toHaveBeenCalledWith(
|
|
"/v1/admin/users/user-id",
|
|
expect.objectContaining({ tenantSlug: "new-tenant" }),
|
|
);
|
|
expect(apiClient.put.mock.calls[0][1]).not.toHaveProperty("companyCode");
|
|
});
|
|
|
|
it("keeps tenantSlug payloads unchanged for bulk user APIs", async () => {
|
|
const { bulkCreateUsers, bulkUpdateUsers } = await import("./adminApi");
|
|
|
|
await bulkCreateUsers([
|
|
{
|
|
email: "user@test.com",
|
|
name: "Test User",
|
|
tenantSlug: "test-tenant",
|
|
metadata: {},
|
|
},
|
|
]);
|
|
await bulkUpdateUsers({
|
|
userIds: ["user-id"],
|
|
tenantSlug: "new-tenant",
|
|
});
|
|
|
|
expect(apiClient.post.mock.calls[0][1].users[0]).toMatchObject({
|
|
tenantSlug: "test-tenant",
|
|
});
|
|
expect(apiClient.post.mock.calls[0][1].users[0]).not.toHaveProperty(
|
|
"companyCode",
|
|
);
|
|
expect(apiClient.put.mock.calls[0][1]).toMatchObject({
|
|
tenantSlug: "new-tenant",
|
|
});
|
|
expect(apiClient.put.mock.calls[0][1]).not.toHaveProperty("companyCode");
|
|
});
|
|
});
|