import { beforeEach, describe, expect, it, vi } from "vitest"; const { mockApi } = vi.hoisted(() => ({ mockApi: { get: vi.fn(), post: vi.fn(), patch: vi.fn(), put: vi.fn(), delete: vi.fn(), }, })); vi.mock("../axios", () => ({ default: mockApi, api: mockApi, })); import { company } from "./companies"; import { credential } from "./credentials"; import { credentialType } from "./credentialTypes"; import { permission } from "./permissions"; import { procurement } from "./procurement"; import { role } from "./roles"; import { sales } from "./sales"; import { unifi } from "./unifi"; import { users } from "./users"; describe("optima api modules", () => { beforeEach(() => { vi.clearAllMocks(); }); it("company.fetchMany sends search params", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: [] } }); await company.fetchMany("token", 2, "acme", 50); expect(mockApi.get).toHaveBeenCalledWith("/v1/company/companies", { params: { page: 2, rpp: 50, search: "acme" }, headers: { Authorization: "Bearer token" }, }); }); it("company.count returns count", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: { count: 17 } } }); const count = await company.count("token"); expect(count).toBe(17); }); it("credential.fetch and delete call expected routes", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: { id: "cred-1" } } }); mockApi.delete.mockResolvedValueOnce({ data: { ok: true } }); await credential.fetch("token", "cred-1"); await credential.delete("token", "cred-1"); expect(mockApi.get).toHaveBeenCalledWith( "/v1/credential/credentials/cred-1", { headers: { Authorization: "Bearer token" }, }, ); expect(mockApi.delete).toHaveBeenCalledWith( "/v1/credential/credentials/cred-1", { headers: { Authorization: "Bearer token" }, }, ); }); it("credential.create posts payload", async () => { const payload = { name: "VPN", notes: "notes", typeId: "type-1", companyId: "company-1", fields: [], }; mockApi.post.mockResolvedValueOnce({ data: { data: payload } }); await credential.create("token", payload as any); expect(mockApi.post).toHaveBeenCalledWith( "/v1/credential/credentials", payload, { headers: { Authorization: "Bearer token" } }, ); }); it("credential.updateFields wraps fields payload", async () => { const fields = [{ id: "f1", name: "Username" }]; mockApi.put.mockResolvedValueOnce({ data: { ok: true } }); await credential.updateFields("token", "cred-1", fields as any); expect(mockApi.put).toHaveBeenCalledWith( "/v1/credential/credentials/cred-1/fields", { fields }, { headers: { Authorization: "Bearer token" } }, ); }); it("credential sub-credential methods call expected endpoints", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: [] } }); mockApi.post.mockResolvedValueOnce({ data: { ok: true } }); mockApi.delete.mockResolvedValueOnce({ data: { ok: true } }); await credential.fetchSubCredentials("token", "cred-1"); await credential.addSubCredential("token", "cred-1", { fieldId: "fid", name: "Sub", fields: [{ fieldId: "f2", value: "v" }], }); await credential.removeSubCredential("token", "cred-1", "sub-1"); expect(mockApi.get).toHaveBeenCalledWith( "/v1/credential/credentials/cred-1/sub-credentials", { headers: { Authorization: "Bearer token" } }, ); expect(mockApi.post).toHaveBeenCalledWith( "/v1/credential/credentials/cred-1/sub-credentials", { fieldId: "fid", name: "Sub", fields: [{ fieldId: "f2", value: "v" }] }, { headers: { Authorization: "Bearer token" } }, ); expect(mockApi.delete).toHaveBeenCalledWith( "/v1/credential/credentials/cred-1/sub-credentials/sub-1", { headers: { Authorization: "Bearer token" } }, ); }); it("credentialType create and delete use identifier path", async () => { mockApi.post.mockResolvedValueOnce({ data: { ok: true } }); mockApi.delete.mockResolvedValueOnce({ data: { ok: true } }); await credentialType.create("token", { name: "Router", permissionScope: "router", fields: [], } as any); await credentialType.delete("token", "ctype-1"); expect(mockApi.post).toHaveBeenCalledWith( "/v1/credential-type", { name: "Router", permissionScope: "router", fields: [] }, { headers: { Authorization: "Bearer token" } }, ); expect(mockApi.delete).toHaveBeenCalledWith("/v1/credential-type/ctype-1", { headers: { Authorization: "Bearer token" }, }); }); it("permission module endpoints are correct", async () => { mockApi.get.mockResolvedValue({ data: { data: [] } }); await permission.fetchCategorized("token"); await permission.fetchFlat("token"); await permission.fetchByCategory("token", "company"); expect(mockApi.get).toHaveBeenNthCalledWith(1, "/v1/permissions", { headers: { Authorization: "Bearer token" }, }); expect(mockApi.get).toHaveBeenNthCalledWith(2, "/v1/permissions/nodes", { headers: { Authorization: "Bearer token" }, }); expect(mockApi.get).toHaveBeenNthCalledWith(3, "/v1/permissions/company", { headers: { Authorization: "Bearer token" }, }); }); it("procurement methods build params and count correctly", async () => { mockApi.get .mockResolvedValueOnce({ data: { data: [] } }) .mockResolvedValueOnce({ data: { data: { count: 4 } } }); await procurement.fetchMany( "token", 3, { search: "switch", includeInactive: true }, 10, ); const count = await procurement.count("token", true); expect(mockApi.get).toHaveBeenNthCalledWith(1, "/v1/procurement/items", { params: { page: 3, rpp: 10, search: "switch", includeInactive: true }, headers: { Authorization: "Bearer token" }, }); expect(mockApi.get).toHaveBeenNthCalledWith(2, "/v1/procurement/count", { params: { activeOnly: "true" }, headers: { Authorization: "Bearer token" }, }); expect(count).toBe(4); }); it("procurement link and unlink post target id", async () => { mockApi.post.mockResolvedValue({ data: { ok: true } }); await procurement.linkItem("token", "item-a", "item-b"); await procurement.unlinkItem("token", "item-a", "item-b"); expect(mockApi.post).toHaveBeenNthCalledWith( 1, "/v1/procurement/items/item-a/link", { targetId: "item-b" }, { headers: { Authorization: "Bearer token" } }, ); expect(mockApi.post).toHaveBeenNthCalledWith( 2, "/v1/procurement/items/item-a/unlink", { targetId: "item-b" }, { headers: { Authorization: "Bearer token" } }, ); }); it("procurement.fetchMany passes all CatalogItemFilters as params", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: [] } }); await procurement.fetchMany("token", 1, { search: "cable", category: "Networking", subcategory: "Ethernet", group: "Cat6", manufacturer: "Ubiquiti", ecosystem: "unifi", inStock: true, minPrice: 10, maxPrice: 500, includeInactive: true, }); expect(mockApi.get).toHaveBeenCalledWith("/v1/procurement/items", { params: { page: 1, rpp: 30, search: "cable", category: "Networking", subcategory: "Ethernet", group: "Cat6", manufacturer: "Ubiquiti", ecosystem: "unifi", inStock: true, minPrice: 10, maxPrice: 500, includeInactive: true, }, headers: { Authorization: "Bearer token" }, }); }); it("procurement.fetchMany omits filters that are not set", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: [] } }); await procurement.fetchMany("token", 2, { category: "Audio" }, 15); expect(mockApi.get).toHaveBeenCalledWith("/v1/procurement/items", { params: { page: 2, rpp: 15, category: "Audio" }, headers: { Authorization: "Bearer token" }, }); }); it("procurement.fetchCategories returns category tree", async () => { const tree = { categories: [{ name: "Net" }], ecosystems: [] }; mockApi.get.mockResolvedValueOnce({ data: { data: tree } }); const result = await procurement.fetchCategories("token"); expect(mockApi.get).toHaveBeenCalledWith("/v1/procurement/categories", { headers: { Authorization: "Bearer token" }, }); expect(result).toEqual(tree); }); it("procurement.fetchFilters passes optional params", async () => { const filterValues = { categories: ["A"], subcategories: ["B"], manufacturers: ["C"], }; mockApi.get.mockResolvedValueOnce({ data: { data: filterValues } }); const result = await procurement.fetchFilters("token", { category: "Networking", subcategory: "Switches", includeInactive: true, }); expect(mockApi.get).toHaveBeenCalledWith("/v1/procurement/filters", { params: { category: "Networking", subcategory: "Switches", includeInactive: "true", }, headers: { Authorization: "Bearer token" }, }); expect(result).toEqual(filterValues); }); it("procurement.fetchFilters works with no options", async () => { const filterValues = { categories: [], subcategories: [], manufacturers: [], }; mockApi.get.mockResolvedValueOnce({ data: { data: filterValues } }); const result = await procurement.fetchFilters("token"); expect(mockApi.get).toHaveBeenCalledWith("/v1/procurement/filters", { params: {}, headers: { Authorization: "Bearer token" }, }); expect(result).toEqual(filterValues); }); it("role add and remove permissions include payload", async () => { mockApi.post.mockResolvedValueOnce({ data: { ok: true } }); mockApi.delete.mockResolvedValueOnce({ data: { ok: true } }); await role.addPermissions("token", "role-1", ["a", "b"]); await role.removePermissions("token", "role-1", ["a"]); expect(mockApi.post).toHaveBeenCalledWith( "/v1/role/role-1/permissions", { permissions: ["a", "b"] }, { headers: { Authorization: "Bearer token" } }, ); expect(mockApi.delete).toHaveBeenCalledWith("/v1/role/role-1/permissions", { headers: { Authorization: "Bearer token" }, data: { permissions: ["a"] }, }); }); it("sales.fetchMany includes includeClosed and search params", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: [] } }); await sales.fetchMany("token", 1, "fiber", 25, true); expect(mockApi.get).toHaveBeenCalledWith("/v1/sales/opportunities", { params: { page: 1, rpp: 25, search: "fiber", includeClosed: true }, headers: { Authorization: "Bearer token" }, }); }); it("sales.fetchOpportunityTypes calls expected endpoint", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: [] } }); await sales.fetchOpportunityTypes("token"); expect(mockApi.get).toHaveBeenCalledWith("/v1/sales/opportunity-types", { headers: { Authorization: "Bearer token" }, }); }); it("sales.fetchOne encodes identifier in URL", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: { id: "opp-1" } } }); await sales.fetchOne("token", "opp-1"); expect(mockApi.get).toHaveBeenCalledWith( "/v1/sales/opportunities/opp-1", { headers: { Authorization: "Bearer token" } }, ); }); it("sales.fetchForecasts calls forecasts endpoint", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: [] } }); await sales.fetchForecasts("token", "opp-1"); expect(mockApi.get).toHaveBeenCalledWith( "/v1/sales/opportunities/opp-1/forecasts", { headers: { Authorization: "Bearer token" } }, ); }); it("sales.fetchProducts calls products endpoint", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: [] } }); await sales.fetchProducts("token", "opp-1"); expect(mockApi.get).toHaveBeenCalledWith( "/v1/sales/opportunities/opp-1/products", { headers: { Authorization: "Bearer token" } }, ); }); it("sales.fetchNotes calls notes endpoint", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: [] } }); await sales.fetchNotes("token", "opp-1"); expect(mockApi.get).toHaveBeenCalledWith( "/v1/sales/opportunities/opp-1/notes", { headers: { Authorization: "Bearer token" } }, ); }); it("sales.createNote posts note payload", async () => { mockApi.post.mockResolvedValueOnce({ data: { id: 1, text: "Hello" } }); await sales.createNote("token", "opp-1", { text: "Hello", flagged: true, }); expect(mockApi.post).toHaveBeenCalledWith( "/v1/sales/opportunities/opp-1/notes", { text: "Hello", flagged: true }, { headers: { Authorization: "Bearer token" } }, ); }); it("sales.updateNote patches with noteId in URL", async () => { mockApi.patch.mockResolvedValueOnce({ data: { ok: true } }); await sales.updateNote("token", "opp-1", 42, { text: "Updated" }); expect(mockApi.patch).toHaveBeenCalledWith( "/v1/sales/opportunities/opp-1/notes/42", { text: "Updated" }, { headers: { Authorization: "Bearer token" } }, ); }); it("sales.deleteNote calls delete with noteId in URL", async () => { mockApi.delete.mockResolvedValueOnce({ data: { ok: true } }); await sales.deleteNote("token", "opp-1", 42); expect(mockApi.delete).toHaveBeenCalledWith( "/v1/sales/opportunities/opp-1/notes/42", { headers: { Authorization: "Bearer token" } }, ); }); it("sales.fetchContacts calls contacts endpoint", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: [] } }); await sales.fetchContacts("token", "opp-1"); expect(mockApi.get).toHaveBeenCalledWith( "/v1/sales/opportunities/opp-1/contacts", { headers: { Authorization: "Bearer token" } }, ); }); it("sales.sequenceProducts patches with ordered IDs", async () => { mockApi.patch.mockResolvedValueOnce({ data: { ok: true } }); await sales.sequenceProducts("token", "opp-1", [3, 1, 2]); expect(mockApi.patch).toHaveBeenCalledWith( "/v1/sales/opportunities/opp-1/products/sequence", { orderedIds: [3, 1, 2] }, { headers: { Authorization: "Bearer token" } }, ); }); it("sales.refreshOpportunity posts to refresh endpoint", async () => { mockApi.post.mockResolvedValueOnce({ data: { ok: true } }); await sales.refreshOpportunity("token", "opp-1"); expect(mockApi.post).toHaveBeenCalledWith( "/v1/sales/opportunities/opp-1/refresh", {}, { headers: { Authorization: "Bearer token" } }, ); }); it("sales.fetchOne encodes special characters in identifier", async () => { mockApi.get.mockResolvedValueOnce({ data: { data: {} } }); await sales.fetchOne("token", "opp/special#1"); expect(mockApi.get).toHaveBeenCalledWith( `/v1/sales/opportunities/${encodeURIComponent("opp/special#1")}`, { headers: { Authorization: "Bearer token" } }, ); }); it("users module uses expected endpoints", async () => { mockApi.get.mockResolvedValue({ data: { data: [] } }); mockApi.post.mockResolvedValueOnce({ data: { data: { results: [] } } }); mockApi.patch.mockResolvedValueOnce({ data: { data: {} } }); mockApi.delete.mockResolvedValueOnce({ data: { data: {} } }); await users.fetchAll("token"); await users.fetch("token", "user-1"); await users.fetchRoles("token", "user-1"); await users.checkPermissions("token", "user-1", ["x"]); await users.update("token", "user-1", { name: "New Name" }); await users.delete("token", "user-1"); expect(mockApi.get).toHaveBeenCalledWith("/v1/user/users", { headers: { Authorization: "Bearer token" }, }); expect(mockApi.get).toHaveBeenCalledWith("/v1/user/users/user-1", { headers: { Authorization: "Bearer token" }, }); expect(mockApi.get).toHaveBeenCalledWith("/v1/user/users/user-1/roles", { headers: { Authorization: "Bearer token" }, }); expect(mockApi.post).toHaveBeenCalledWith( "/v1/user/users/user-1/check-permission", { permissions: ["x"] }, { headers: { Authorization: "Bearer token" } }, ); }); it("unifi module hits expected endpoints for site and wifi actions", async () => { mockApi.get.mockResolvedValue({ data: { data: [] } }); mockApi.post.mockResolvedValue({ data: { ok: true } }); mockApi.patch.mockResolvedValue({ data: { ok: true } }); await unifi.fetchSites("token"); await unifi.syncSites("token"); await unifi.createSite("token", "HQ"); await unifi.linkSite("token", "site-1", "company-1"); await unifi.unlinkSite("token", "site-1"); await unifi.fetchSiteWifi("token", "site-1"); await unifi.updateWifi("token", "site-1", "wlan-1", { name: "New" }); await unifi.fetchPPSKs("token", "site-1", "wlan-1"); await unifi.createPPSK("token", "site-1", "wlan-1", { key: "abc", name: "Staff", }); expect(mockApi.get).toHaveBeenCalledWith("/v1/unifi/sites", { headers: { Authorization: "Bearer token" }, }); expect(mockApi.post).toHaveBeenCalledWith( "/v1/unifi/sites/sync", {}, { headers: { Authorization: "Bearer token" } }, ); expect(mockApi.patch).toHaveBeenCalledWith( "/v1/unifi/site/site-1/wifi/wlan-1", { name: "New" }, { headers: { Authorization: "Bearer token" } }, ); }); });