mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-04 19:21:51 +00:00
5b9824c379
Co-authored-by: Pablo F.G <pablo.fernandez@prowler.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
139 lines
3.9 KiB
TypeScript
139 lines
3.9 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const {
|
|
fetchMock,
|
|
getAuthHeadersMock,
|
|
handleApiErrorMock,
|
|
handleApiResponseMock,
|
|
} = vi.hoisted(() => ({
|
|
fetchMock: vi.fn(),
|
|
getAuthHeadersMock: vi.fn(),
|
|
handleApiErrorMock: vi.fn(),
|
|
handleApiResponseMock: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("next/cache", () => ({
|
|
revalidatePath: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("next/navigation", () => ({
|
|
redirect: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("@/lib", () => ({
|
|
apiBaseUrl: "https://api.example.com/api/v1",
|
|
getAuthHeaders: getAuthHeadersMock,
|
|
getErrorMessage: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("@/lib/server-actions-helper", () => ({
|
|
handleApiError: handleApiErrorMock,
|
|
handleApiResponse: handleApiResponseMock,
|
|
}));
|
|
|
|
import { getAllProviderGroups } from "./manage-groups";
|
|
|
|
const makeGroup = (id: string, name: string) => ({
|
|
type: "provider-groups" as const,
|
|
id,
|
|
attributes: { name, inserted_at: "", updated_at: "" },
|
|
relationships: {
|
|
providers: { meta: { count: 0 }, data: [] },
|
|
roles: { meta: { count: 0 }, data: [] },
|
|
},
|
|
links: { self: "" },
|
|
});
|
|
|
|
const makePage = (
|
|
data: ReturnType<typeof makeGroup>[],
|
|
page: number,
|
|
pages: number,
|
|
) => ({
|
|
links: { first: "", last: "", next: null, prev: null },
|
|
data,
|
|
meta: { pagination: { page, pages, count: data.length } },
|
|
});
|
|
|
|
describe("getAllProviderGroups", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
getAuthHeadersMock.mockResolvedValue({ Authorization: "Bearer token" });
|
|
fetchMock.mockResolvedValue(new Response(null, { status: 200 }));
|
|
});
|
|
|
|
it("merges every page into a single response with collapsed pagination", async () => {
|
|
handleApiResponseMock
|
|
.mockResolvedValueOnce(
|
|
makePage(
|
|
[makeGroup("g1", "Group 1"), makeGroup("g2", "Group 2")],
|
|
1,
|
|
2,
|
|
),
|
|
)
|
|
.mockResolvedValueOnce(makePage([makeGroup("g3", "Group 3")], 2, 2));
|
|
|
|
const result = await getAllProviderGroups();
|
|
|
|
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
expect(result?.data.map((group) => group.id)).toEqual(["g1", "g2", "g3"]);
|
|
expect(result?.meta.pagination).toMatchObject({
|
|
page: 1,
|
|
pages: 1,
|
|
count: 3,
|
|
});
|
|
});
|
|
|
|
it("stops after the first page when there is only one page", async () => {
|
|
handleApiResponseMock.mockResolvedValueOnce(
|
|
makePage([makeGroup("g1", "Group 1")], 1, 1),
|
|
);
|
|
|
|
const result = await getAllProviderGroups();
|
|
|
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
expect(result?.data).toHaveLength(1);
|
|
});
|
|
|
|
it("returns undefined when the first page has no data", async () => {
|
|
handleApiResponseMock.mockResolvedValueOnce(makePage([], 1, 1));
|
|
|
|
const result = await getAllProviderGroups();
|
|
|
|
expect(result).toBeUndefined();
|
|
});
|
|
|
|
it("returns undefined when the request throws", async () => {
|
|
fetchMock.mockRejectedValueOnce(new Error("network down"));
|
|
|
|
const result = await getAllProviderGroups();
|
|
|
|
expect(result).toBeUndefined();
|
|
});
|
|
|
|
it("returns undefined when a later page resolves to an error payload", async () => {
|
|
handleApiResponseMock
|
|
.mockResolvedValueOnce(makePage([makeGroup("g1", "Group 1")], 1, 2))
|
|
.mockResolvedValueOnce({ error: "Forbidden", status: 403 });
|
|
|
|
const result = await getAllProviderGroups();
|
|
|
|
expect(result).toBeUndefined();
|
|
});
|
|
|
|
it("returns undefined instead of a truncated list when the max-page cap is hit", async () => {
|
|
// Given an API that always reports more pages than the 50-page safety cap
|
|
handleApiResponseMock.mockImplementation((response: Response) => {
|
|
void response;
|
|
return Promise.resolve(makePage([makeGroup("g", "Group")], 1, 9999));
|
|
});
|
|
|
|
// When fetching every page
|
|
const result = await getAllProviderGroups();
|
|
|
|
// Then it must not return a partial/truncated list; bail out instead
|
|
expect(result).toBeUndefined();
|
|
expect(fetchMock).toHaveBeenCalledTimes(50);
|
|
});
|
|
});
|