mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-11-09 04:38:49 +00:00
feat(ui): show the attack path in the Issues panel and rename the menu entry (#13195)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
814ae54d6a
commit
ca6ed48664
20 files changed
+461
-109
No files matched your search
@@ -0,0 +1,67 @@
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const { useFeatureFlagStateMock, redirect } = vi.hoisted(() => ({
|
||||
useFeatureFlagStateMock: vi.fn(),
|
||||
redirect: vi.fn(() => {
|
||||
throw new Error("REDIRECT");
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("next/navigation", () => ({ redirect }));
|
||||
vi.mock("@/lib/feature-flags", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("@/lib/feature-flags")>()),
|
||||
useFeatureFlagState: useFeatureFlagStateMock,
|
||||
}));
|
||||
|
||||
import { FEATURE_FLAG, FEATURE_FLAG_STATE } from "@/lib/feature-flags";
|
||||
|
||||
import { FeatureFlagRoute } from "./feature-flag-route";
|
||||
|
||||
const renderRoute = () =>
|
||||
render(
|
||||
<FeatureFlagRoute flag={FEATURE_FLAG.ISSUES}>
|
||||
<p>route content</p>
|
||||
</FeatureFlagRoute>,
|
||||
);
|
||||
|
||||
describe("FeatureFlagRoute", () => {
|
||||
beforeEach(() => {
|
||||
useFeatureFlagStateMock.mockReset();
|
||||
redirect.mockClear();
|
||||
});
|
||||
|
||||
it("sends the user to the overview once the flag resolves off", () => {
|
||||
// Given
|
||||
useFeatureFlagStateMock.mockReturnValue(FEATURE_FLAG_STATE.OFF);
|
||||
vi.spyOn(console, "error").mockImplementation(() => {});
|
||||
|
||||
// When / Then
|
||||
expect(renderRoute).toThrow("REDIRECT");
|
||||
expect(redirect).toHaveBeenCalledWith("/");
|
||||
});
|
||||
|
||||
it("renders the route once the flag resolves on", () => {
|
||||
// Given
|
||||
useFeatureFlagStateMock.mockReturnValue(FEATURE_FLAG_STATE.ON);
|
||||
|
||||
// When
|
||||
renderRoute();
|
||||
|
||||
// Then
|
||||
expect(screen.getByText("route content")).toBeInTheDocument();
|
||||
expect(redirect).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("renders nothing while the flag is unresolved", () => {
|
||||
// Given
|
||||
useFeatureFlagStateMock.mockReturnValue(FEATURE_FLAG_STATE.PENDING);
|
||||
|
||||
// When
|
||||
const { container } = renderRoute();
|
||||
|
||||
// Then
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
expect(redirect).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
"use client";
|
||||
|
||||
import { redirect } from "next/navigation";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import { FeatureFlagGate } from "@/components/shared/feature-flag-gate";
|
||||
import type { FeatureFlag } from "@/lib/feature-flags";
|
||||
|
||||
const ToOverview = (): never => redirect("/");
|
||||
|
||||
interface FeatureFlagRouteProps {
|
||||
flag: FeatureFlag;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
// A route behind a flag: off sends the user to the overview, pending renders
|
||||
// nothing. Same client evaluation as the menu entry, so the link and the
|
||||
// route never disagree.
|
||||
export function FeatureFlagRoute({ flag, children }: FeatureFlagRouteProps) {
|
||||
return (
|
||||
<FeatureFlagGate flag={flag} fallback={<ToOverview />}>
|
||||
{children}
|
||||
</FeatureFlagGate>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user