Files
prowler/ui/lib/menu-list.test.ts
Pedro Martín 69321418a3 feat(ui): improve scan config ux (#11731)
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
2026-07-01 15:45:38 +02:00

147 lines
4.0 KiB
TypeScript

import { afterEach, describe, expect, it } from "vitest";
import { getMenuList } from "./menu-list";
const findMenu = (label: string) =>
getMenuList({ pathname: "/alerts" })
.flatMap((group) => group.menus)
.find((menu) => menu.label === label);
const findSubmenu = (label: string) =>
getMenuList({ pathname: "/alerts" })
.flatMap((group) => group.menus)
.flatMap((menu) => menu.submenus ?? [])
.find((submenu) => submenu.label === label);
const findApiReference = (options: Parameters<typeof getMenuList>[0]) =>
getMenuList(options)
.flatMap((group) => group.menus)
.flatMap((menu) => menu.submenus ?? [])
.find((submenu) => submenu.label === "API reference");
describe("getMenuList", () => {
afterEach(() => {
delete process.env.NEXT_PUBLIC_IS_CLOUD_ENV;
});
describe("API reference link", () => {
it("should use the apiDocsUrl provided by the caller in OSS", () => {
// Given / When — the caller resolves the runtime value (hydration-safe)
const apiRef = findApiReference({
pathname: "/",
apiDocsUrl: "https://self-hosted.example/api/v1/docs",
});
// Then
expect(apiRef?.href).toBe("https://self-hosted.example/api/v1/docs");
});
it("should default to an empty href when no apiDocsUrl is provided", () => {
// Given / When — no island read here, so SSR and client agree
const apiRef = findApiReference({ pathname: "/" });
// Then
expect(apiRef?.href).toBe("");
});
it("should use the Cloud docs URL and ignore apiDocsUrl when Cloud is enabled", () => {
// Given
process.env.NEXT_PUBLIC_IS_CLOUD_ENV = "true";
// When
const apiRef = findApiReference({
pathname: "/",
apiDocsUrl: "https://ignored.example/docs",
});
// Then
expect(apiRef?.href).toBe("https://api.prowler.com/api/v1/docs");
});
});
it("should show Alerts as disabled Cloud-only in OSS when Cloud is disabled", () => {
// Given / When
const alerts = findSubmenu("Alerts");
// Then
expect(alerts).toEqual(
expect.objectContaining({
href: "/alerts",
disabled: true,
cloudOnly: true,
highlight: true,
active: false,
}),
);
});
it("should show Alerts as new under Configuration when Cloud is enabled", () => {
// Given
process.env.NEXT_PUBLIC_IS_CLOUD_ENV = "true";
// When
const alerts = findSubmenu("Alerts");
// Then
expect(alerts).toEqual(
expect.objectContaining({
href: "/alerts",
active: true,
highlight: true,
}),
);
});
it("should show Scan as disabled Cloud-only in OSS when Cloud is disabled", () => {
// Given / When
const scanConfig = findSubmenu("Scan");
// Then
expect(scanConfig).toEqual(
expect.objectContaining({
href: "/scans/config",
disabled: true,
cloudOnly: true,
highlight: true,
active: false,
}),
);
});
it("should show Scan as new under Configuration when Cloud is enabled", () => {
// Given
process.env.NEXT_PUBLIC_IS_CLOUD_ENV = "true";
// When
const menus = getMenuList({ pathname: "/scans/config" }).flatMap(
(group) => group.menus,
);
const scanConfig = menus
.flatMap((menu) => menu.submenus ?? [])
.find((submenu) => submenu.label === "Scan");
const scans = menus.find((menu) => menu.label === "Scans");
// Then
expect(scanConfig).toEqual(
expect.objectContaining({
href: "/scans/config",
active: true,
highlight: true,
}),
);
// The top-level Scans item uses an exact-match active rule, so it must stay
// inactive on the `/scans/config` sub-route.
expect(scans).toEqual(expect.objectContaining({ active: false }));
});
it("should remove the new highlight from Attack Paths", () => {
// Given / When
const attackPaths = findMenu("Attack Paths");
// Then
expect(attackPaths).toEqual(
expect.not.objectContaining({ highlight: true }),
);
});
});