mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-12 06:24:14 +00:00
303 lines
8.5 KiB
TypeScript
303 lines
8.5 KiB
TypeScript
import { render, screen } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import {
|
|
afterEach,
|
|
beforeAll,
|
|
beforeEach,
|
|
describe,
|
|
expect,
|
|
it,
|
|
vi,
|
|
} from "vitest";
|
|
|
|
import { SIDEBAR_NAVIGATION_MODE } from "@/hooks/use-sidebar";
|
|
|
|
const {
|
|
openLaunchScanModalMock,
|
|
openCloudUpgradeMock,
|
|
pathnameValue,
|
|
pushMock,
|
|
navigationModeValue,
|
|
setNavigationModeMock,
|
|
} = vi.hoisted(() => ({
|
|
openLaunchScanModalMock: vi.fn(),
|
|
openCloudUpgradeMock: vi.fn(),
|
|
pathnameValue: { current: "/findings" },
|
|
pushMock: vi.fn(),
|
|
navigationModeValue: { current: "browse" },
|
|
setNavigationModeMock: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("next/navigation", () => ({
|
|
usePathname: () => pathnameValue.current,
|
|
useRouter: () => ({
|
|
push: pushMock,
|
|
}),
|
|
}));
|
|
|
|
vi.mock("next-auth/react", () => ({
|
|
useSession: () => ({
|
|
data: { user: { permissions: {} } },
|
|
status: "authenticated",
|
|
}),
|
|
}));
|
|
|
|
vi.mock("@/hooks", () => ({
|
|
useAuth: () => ({
|
|
permissions: {},
|
|
}),
|
|
}));
|
|
|
|
vi.mock("@/lib/menu-list", () => ({
|
|
getMenuList: () => [],
|
|
}));
|
|
|
|
vi.mock("@/app/(prowler)/lighthouse/_components/navigation", () => ({
|
|
LighthouseV2SidebarChat: () => <div data-testid="lighthouse-chat-sidebar" />,
|
|
}));
|
|
|
|
vi.mock("@/store", () => ({
|
|
useScansStore: (
|
|
selector: (state: { openLaunchScanModal: () => void }) => unknown,
|
|
) => selector({ openLaunchScanModal: openLaunchScanModalMock }),
|
|
useCloudUpgradeStore: (
|
|
selector: (state: {
|
|
openCloudUpgrade: (feature: string) => void;
|
|
}) => unknown,
|
|
) => selector({ openCloudUpgrade: openCloudUpgradeMock }),
|
|
}));
|
|
|
|
vi.mock("@/hooks/use-sidebar", async (importActual) => {
|
|
const actual = await importActual<typeof import("@/hooks/use-sidebar")>();
|
|
return {
|
|
...actual,
|
|
useSidebar: (
|
|
selector: (state: {
|
|
navigationMode: string;
|
|
setNavigationMode: (mode: string) => void;
|
|
}) => unknown,
|
|
) =>
|
|
selector({
|
|
navigationMode: navigationModeValue.current,
|
|
setNavigationMode: setNavigationModeMock,
|
|
}),
|
|
};
|
|
});
|
|
|
|
let MenuComponent: typeof import("./menu").Menu;
|
|
let SidebarNavigationModeToggleComponent: typeof import("@/components/sidebar/navigation-mode-toggle").SidebarNavigationModeToggle;
|
|
|
|
const expectLastCloudUpgrade = (feature: string) => {
|
|
expect(openCloudUpgradeMock.mock.calls.at(-1)?.[0]).toBe(feature);
|
|
};
|
|
|
|
beforeAll(async () => {
|
|
MenuComponent = (await import("./menu")).Menu;
|
|
SidebarNavigationModeToggleComponent = (
|
|
await import("@/components/sidebar/navigation-mode-toggle")
|
|
).SidebarNavigationModeToggle;
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllEnvs();
|
|
navigationModeValue.current = "browse";
|
|
openCloudUpgradeMock.mockClear();
|
|
});
|
|
|
|
describe("Menu", () => {
|
|
it("links scan to the scans page with the modal open", () => {
|
|
pathnameValue.current = "/findings";
|
|
|
|
render(<MenuComponent isOpen />);
|
|
|
|
const launchScanLink = screen.getByRole("link", { name: /launch scan/i });
|
|
const launchScanWrapper = launchScanLink.closest("div.flex.shrink-0");
|
|
|
|
expect(launchScanLink).toHaveAttribute("href", "/scans?launchScan=true");
|
|
expect(launchScanWrapper).toHaveClass("flex", "justify-center");
|
|
expect(launchScanLink).toHaveClass("h-14", "w-full", "p-1");
|
|
expect(launchScanLink).not.toHaveClass("h-8", "h-9", "h-10");
|
|
expect(screen.getByText("Scan")).toHaveClass("text-xl", "leading-8");
|
|
expect(screen.getByText("Scan")).not.toHaveClass("text-2xl", "font-bold");
|
|
expect(
|
|
launchScanLink.querySelector('svg[viewBox="0 0 432.08 396.77"]'),
|
|
).toBeInTheDocument();
|
|
});
|
|
|
|
it("opens the launch scan modal without navigation when already on scans", async () => {
|
|
pathnameValue.current = "/scans";
|
|
|
|
render(<MenuComponent isOpen />);
|
|
|
|
await screen.getByRole("button", { name: /launch scan/i }).click();
|
|
|
|
expect(openLaunchScanModalMock).toHaveBeenCalledTimes(1);
|
|
expect(
|
|
screen.queryByRole("link", { name: /launch scan/i }),
|
|
).not.toBeInTheDocument();
|
|
});
|
|
|
|
it("shows the Prowler icon when the menu is collapsed", () => {
|
|
pathnameValue.current = "/findings";
|
|
|
|
render(<MenuComponent isOpen={false} />);
|
|
|
|
const launchScanLink = screen.getByRole("link", { name: /launch scan/i });
|
|
|
|
expect(launchScanLink).toHaveClass("h-9", "w-14");
|
|
expect(launchScanLink).not.toHaveClass("h-14");
|
|
expect(
|
|
launchScanLink.querySelector('svg[viewBox="0 0 432.08 396.77"]'),
|
|
).toBeInTheDocument();
|
|
});
|
|
|
|
it("swaps to the Lighthouse chat sidebar in cloud CHAT mode", () => {
|
|
pathnameValue.current = "/lighthouse";
|
|
vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "true");
|
|
navigationModeValue.current = SIDEBAR_NAVIGATION_MODE.CHAT;
|
|
|
|
render(<MenuComponent isOpen />);
|
|
|
|
expect(screen.getByTestId("lighthouse-chat-sidebar")).toBeInTheDocument();
|
|
expect(screen.getByRole("button", { name: "Chat" })).toBeInTheDocument();
|
|
});
|
|
|
|
it("keeps the navigation menu in cloud BROWSE mode", () => {
|
|
pathnameValue.current = "/findings";
|
|
vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "true");
|
|
navigationModeValue.current = SIDEBAR_NAVIGATION_MODE.BROWSE;
|
|
|
|
render(<MenuComponent isOpen />);
|
|
|
|
expect(
|
|
screen.queryByTestId("lighthouse-chat-sidebar"),
|
|
).not.toBeInTheDocument();
|
|
expect(screen.getByRole("button", { name: "Home" })).toBeInTheDocument();
|
|
});
|
|
|
|
it("opens the managed Lighthouse upgrade from Chat in Local Server", async () => {
|
|
pathnameValue.current = "/findings";
|
|
vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "false");
|
|
|
|
render(<MenuComponent isOpen />);
|
|
|
|
expect(screen.getByRole("button", { name: "Home" })).toBeInTheDocument();
|
|
const chatButton = screen.getByRole("button", { name: "Chat" });
|
|
expect(chatButton).not.toHaveAttribute("aria-disabled");
|
|
|
|
await userEvent.click(chatButton);
|
|
|
|
expectLastCloudUpgrade("lighthouse_ai");
|
|
});
|
|
|
|
it("shows a persistent Cloud upgrade action only in Local Server", async () => {
|
|
pathnameValue.current = "/findings";
|
|
vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "false");
|
|
|
|
render(<MenuComponent isOpen />);
|
|
|
|
const upgradeButton = screen.getByRole("button", {
|
|
name: "Explore Prowler Cloud",
|
|
});
|
|
expect(upgradeButton).toHaveClass("bg-button-primary");
|
|
|
|
await userEvent.click(upgradeButton);
|
|
|
|
expectLastCloudUpgrade("general");
|
|
});
|
|
|
|
it("separates the persistent Cloud upgrade action from the navigation", () => {
|
|
// Given
|
|
pathnameValue.current = "/findings";
|
|
vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "false");
|
|
|
|
// When
|
|
render(<MenuComponent isOpen />);
|
|
|
|
// Then
|
|
expect(
|
|
screen.getByRole("button", { name: "Explore Prowler Cloud" })
|
|
.parentElement,
|
|
).toHaveClass("pt-4");
|
|
});
|
|
});
|
|
|
|
describe("SidebarNavigationModeToggle", () => {
|
|
beforeEach(() => {
|
|
pushMock.mockClear();
|
|
});
|
|
|
|
it("navigates to Lighthouse when Chat mode is selected", async () => {
|
|
// Given
|
|
const user = userEvent.setup();
|
|
const onChange = vi.fn();
|
|
|
|
render(
|
|
<SidebarNavigationModeToggleComponent
|
|
isOpen
|
|
value={SIDEBAR_NAVIGATION_MODE.BROWSE}
|
|
onChange={onChange}
|
|
/>,
|
|
);
|
|
|
|
// When
|
|
await user.click(screen.getByRole("button", { name: "Chat" }));
|
|
|
|
// Then
|
|
expect(onChange).toHaveBeenCalledWith(SIDEBAR_NAVIGATION_MODE.CHAT);
|
|
expect(pushMock).toHaveBeenCalledWith("/lighthouse");
|
|
});
|
|
|
|
it("does not navigate when Home mode is selected", async () => {
|
|
// Given
|
|
const user = userEvent.setup();
|
|
const onChange = vi.fn();
|
|
|
|
render(
|
|
<SidebarNavigationModeToggleComponent
|
|
isOpen
|
|
value={SIDEBAR_NAVIGATION_MODE.CHAT}
|
|
onChange={onChange}
|
|
/>,
|
|
);
|
|
|
|
// When
|
|
await user.click(screen.getByRole("button", { name: "Home" }));
|
|
|
|
// Then
|
|
expect(onChange).toHaveBeenCalledWith(SIDEBAR_NAVIGATION_MODE.BROWSE);
|
|
expect(pushMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("opens the Cloud upgrade and shows the cloud tooltip when chat is unavailable", async () => {
|
|
// Given
|
|
const user = userEvent.setup();
|
|
const onChange = vi.fn();
|
|
|
|
render(
|
|
<SidebarNavigationModeToggleComponent
|
|
isOpen
|
|
value={SIDEBAR_NAVIGATION_MODE.BROWSE}
|
|
onChange={onChange}
|
|
chatEnabled={false}
|
|
/>,
|
|
);
|
|
|
|
// When
|
|
const chatButton = screen.getByRole("button", { name: "Chat" });
|
|
await user.hover(chatButton);
|
|
|
|
// Then
|
|
const tooltip = await screen.findByRole("tooltip");
|
|
expect(tooltip).toHaveTextContent("Available in Prowler Cloud");
|
|
|
|
// When
|
|
await user.click(chatButton);
|
|
|
|
// Then
|
|
expect(onChange).not.toHaveBeenCalled();
|
|
expect(pushMock).not.toHaveBeenCalled();
|
|
expectLastCloudUpgrade("lighthouse_ai");
|
|
});
|
|
});
|