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(), }; 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("adminApi endpoint contracts", () => { beforeEach(() => { apiClient.get.mockReset(); apiClient.post.mockReset(); apiClient.put.mockReset(); apiClient.patch.mockReset(); apiClient.delete.mockReset(); apiClient.get.mockResolvedValue({ data: { ok: true }, headers: { "content-disposition": 'attachment; filename="export.csv"' }, }); apiClient.post.mockResolvedValue({ data: { ok: true } }); apiClient.put.mockResolvedValue({ data: { ok: true } }); apiClient.patch.mockResolvedValue({ data: { ok: true } }); apiClient.delete.mockResolvedValue({ data: { ok: true } }); fetchAllCursorPages.mockClear(); window.localStorage.clear(); }); it("routes read APIs to their documented admin endpoints", async () => { const adminApi = await import("./adminApi"); await adminApi.fetchAuditLogs(10, "cursor-a"); await adminApi.fetchAdminOverviewStats(); await adminApi.fetchDataIntegrityReport(); await adminApi.fetchOrphanUserLoginIDs(); await adminApi.fetchUserProjectionStatus(); await adminApi.fetchAdminRPUsageDaily({ days: 30, period: "week", tenantId: "tenant-1", }); 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.fetchGroupRoles("tenant-1", "group-1"); await adminApi.fetchApiKeys(20, 40); await adminApi.fetchUsers(30, 60, "admin", "tenant"); await adminApi.fetchUser("user-1"); await adminApi.fetchWorksmobileOverview("tenant-1"); await adminApi.fetchWorksmobileComparison("tenant-1", true); await adminApi.downloadWorksmobileInitialPasswordsCSV("tenant-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"); 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/worksmobile/comparison", { params: { includeMatched: true } }, ); expect(await adminApi.exportTenantsCSV(true, "parent-1")).toMatchObject({ filename: "export.csv", }); expect( await adminApi.exportUsersCSV("admin", "tenant", true), ).toMatchObject({ filename: "export.csv", }); }); it("routes mutation APIs to their documented admin endpoints", async () => { const adminApi = await import("./adminApi"); await adminApi.deleteOrphanUserLoginIDs(["orphan-1"]); await adminApi.reconcileUserProjection(); await adminApi.resetUserProjection(); 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.importTenantsCSV(new File(["name"], "tenants.csv")); 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.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.updateApiKeyScopes("key-1", { scopes: ["write"] }); await adminApi.rotateApiKeySecret("key-1"); 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.enqueueWorksmobileBackfillDryRun("tenant-1"); await adminApi.enqueueWorksmobileOrgUnitSync("tenant-1", "org/unit"); await adminApi.enqueueWorksmobileOrgUnitDelete("tenant-1", "org/unit"); await adminApi.enqueueWorksmobileUserSync("tenant-1", "user-1"); await adminApi.retryWorksmobileJob("tenant-1", "job-1"); 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.delete).toHaveBeenCalledWith( "/v1/admin/integrity/orphan-user-login-ids", { data: { ids: ["orphan-1"] } }, ); expect(apiClient.post).toHaveBeenCalledWith( "/v1/admin/projections/users/reconcile", ); expect(apiClient.put).toHaveBeenCalledWith("/v1/admin/users/user-1", { status: "active", }); expect(apiClient.post).toHaveBeenCalledWith( "/v1/admin/tenants/tenant-1/worksmobile/orgunits/org%2Funit/sync", ); expect(apiClient.delete).toHaveBeenCalledWith( "/v1/admin/relying-parties/client-1/owners/User:user-1", ); }); });