mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-11-09 04:38:49 +00:00
209 lines
4.9 KiB
TypeScript
209 lines
4.9 KiB
TypeScript
import { render, screen, within } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
|
|
import type { MembershipDetailData, TenantDetailData } from "@/types/users";
|
|
|
|
import { MembershipsCardClient } from "./memberships-card-client";
|
|
|
|
vi.mock("next/navigation", () => ({
|
|
usePathname: () => "/profile",
|
|
useRouter: () => ({
|
|
push: vi.fn(),
|
|
}),
|
|
useSearchParams: () => new URLSearchParams(),
|
|
}));
|
|
|
|
vi.mock("@/contexts", () => ({
|
|
useFilterTransitionOptional: () => null,
|
|
}));
|
|
|
|
vi.mock("@/lib", () => ({
|
|
getPaginationInfo: () => ({
|
|
currentPage: 1,
|
|
totalPages: 1,
|
|
totalEntries: 1,
|
|
itemsPerPageOptions: [10, 20, 50],
|
|
}),
|
|
}));
|
|
|
|
vi.mock("@/components/users/forms/create-tenant-form", () => ({
|
|
CreateTenantForm: () => <div>Create organization form</div>,
|
|
}));
|
|
|
|
vi.mock("@/components/users/forms", () => ({
|
|
EditTenantForm: () => <div>Edit organization form</div>,
|
|
}));
|
|
|
|
vi.mock("@/components/users/forms/delete-tenant-form", () => ({
|
|
DeleteTenantForm: () => <div>Delete organization form</div>,
|
|
}));
|
|
|
|
vi.mock("@/components/users/forms/switch-tenant-form", () => ({
|
|
SwitchTenantForm: () => <div>Switch organization form</div>,
|
|
}));
|
|
|
|
vi.mock("@/components/shadcn", async (importOriginal) => ({
|
|
...(await importOriginal<Record<string, unknown>>()),
|
|
useToast: () => ({ toast: vi.fn() }),
|
|
}));
|
|
|
|
const memberships = [
|
|
{
|
|
id: "membership-1",
|
|
type: "memberships",
|
|
attributes: {
|
|
role: "owner",
|
|
date_joined: "2026-06-09T10:00:00Z",
|
|
},
|
|
relationships: {
|
|
tenant: {
|
|
data: {
|
|
type: "tenants",
|
|
id: "tenant-1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
] satisfies MembershipDetailData[];
|
|
|
|
const inactiveMembership = {
|
|
id: "membership-2",
|
|
type: "memberships",
|
|
attributes: {
|
|
role: "owner",
|
|
date_joined: "2026-06-23T10:00:00Z",
|
|
},
|
|
relationships: {
|
|
tenant: {
|
|
data: {
|
|
type: "tenants",
|
|
id: "tenant-2",
|
|
},
|
|
},
|
|
},
|
|
} satisfies MembershipDetailData;
|
|
|
|
const tenantsMap = {
|
|
"tenant-1": {
|
|
id: "tenant-1",
|
|
type: "tenants",
|
|
attributes: {
|
|
name: "Prowler Labs",
|
|
},
|
|
relationships: {
|
|
memberships: {
|
|
meta: {
|
|
count: 1,
|
|
},
|
|
data: [],
|
|
},
|
|
},
|
|
},
|
|
"tenant-2": {
|
|
id: "tenant-2",
|
|
type: "tenants",
|
|
attributes: {
|
|
name: "Prowler Sandbox",
|
|
},
|
|
relationships: {
|
|
memberships: {
|
|
meta: {
|
|
count: 1,
|
|
},
|
|
data: [],
|
|
},
|
|
},
|
|
},
|
|
} satisfies Record<string, TenantDetailData>;
|
|
|
|
describe("MembershipsCardClient", () => {
|
|
it("renders organizations in a table with the active status before the name", () => {
|
|
// When
|
|
render(
|
|
<MembershipsCardClient
|
|
memberships={memberships}
|
|
tenantsMap={tenantsMap}
|
|
hasManageAccount
|
|
sessionTenantId="tenant-1"
|
|
/>,
|
|
);
|
|
|
|
// Then
|
|
expect(screen.getByRole("table")).toBeInTheDocument();
|
|
expect(
|
|
screen.getByRole("columnheader", { name: "Role" }),
|
|
).toBeInTheDocument();
|
|
expect(
|
|
screen.getByRole("columnheader", { name: "Status" }),
|
|
).toBeInTheDocument();
|
|
expect(
|
|
screen.getByRole("columnheader", { name: "Name" }),
|
|
).toBeInTheDocument();
|
|
|
|
const row = screen.getByRole("row", {
|
|
name: /owner active prowler labs/i,
|
|
});
|
|
const cells = within(row).getAllByRole("cell");
|
|
|
|
expect(cells[0]).toHaveTextContent("owner");
|
|
expect(cells[1]).toHaveTextContent("Active");
|
|
expect(cells[2]).toHaveTextContent("Prowler Labs");
|
|
});
|
|
|
|
it("leaves inactive organization status empty", () => {
|
|
// Given / When
|
|
render(
|
|
<MembershipsCardClient
|
|
memberships={[...memberships, inactiveMembership]}
|
|
tenantsMap={tenantsMap}
|
|
hasManageAccount
|
|
sessionTenantId="tenant-1"
|
|
/>,
|
|
);
|
|
|
|
// Then
|
|
const inactiveRow = screen.getByRole("row", {
|
|
name: /owner prowler sandbox/i,
|
|
});
|
|
expect(within(inactiveRow).queryByText("Inactive")).not.toBeInTheDocument();
|
|
expect(screen.getByText("Active")).toBeInTheDocument();
|
|
});
|
|
|
|
it("keeps organization edit and delete actions inside the actions menu", async () => {
|
|
// Given
|
|
const user = userEvent.setup();
|
|
|
|
render(
|
|
<MembershipsCardClient
|
|
memberships={memberships}
|
|
tenantsMap={tenantsMap}
|
|
hasManageAccount
|
|
sessionTenantId="tenant-1"
|
|
/>,
|
|
);
|
|
|
|
// When
|
|
expect(
|
|
screen.queryByRole("button", { name: "Edit" }),
|
|
).not.toBeInTheDocument();
|
|
expect(
|
|
screen.queryByRole("button", { name: "Delete" }),
|
|
).not.toBeInTheDocument();
|
|
|
|
await user.click(
|
|
screen.getByRole("button", {
|
|
name: "Open actions menu",
|
|
}),
|
|
);
|
|
|
|
// Then
|
|
expect(
|
|
screen.getByRole("menuitem", { name: /edit organization/i }),
|
|
).toBeInTheDocument();
|
|
expect(
|
|
screen.getByRole("menuitem", { name: /delete organization/i }),
|
|
).toBeInTheDocument();
|
|
});
|
|
});
|