Files
prowler/ui/components/scans/edit-alias-modal.test.tsx
2026-07-08 16:57:02 +02:00

204 lines
5.2 KiB
TypeScript

import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { beforeEach, describe, expect, it, vi } from "vitest";
const { refreshMock, updateScanMock, toastMock } = vi.hoisted(() => ({
refreshMock: vi.fn(),
updateScanMock: vi.fn(),
toastMock: vi.fn(),
}));
vi.mock("next/navigation", () => ({
useRouter: () => ({ refresh: refreshMock }),
}));
vi.mock("@/actions/scans", () => ({
updateScan: updateScanMock,
}));
vi.mock("@/components/shadcn/toast", () => ({
toast: toastMock,
}));
vi.mock("@/components/shadcn/modal", () => ({
Modal: ({
children,
open,
title,
}: {
children: React.ReactNode;
open: boolean;
title: string;
}) =>
open ? (
<div role="dialog" aria-label={title}>
{children}
</div>
) : null,
}));
import { EditAliasModal } from "./edit-alias-modal";
describe("EditAliasModal", () => {
beforeEach(() => {
vi.clearAllMocks();
updateScanMock.mockResolvedValue({});
});
it("seeds the input with the current alias", () => {
render(
<EditAliasModal
open
onOpenChange={vi.fn()}
scanId="scan-1"
currentAlias="Production audit"
/>,
);
expect(screen.getByLabelText("Alias")).toHaveValue("Production audit");
});
it("rejects an unchanged alias before calling the action", async () => {
const user = userEvent.setup();
render(
<EditAliasModal
open
onOpenChange={vi.fn()}
scanId="scan-1"
currentAlias="Production audit"
/>,
);
await user.click(screen.getByRole("button", { name: /save/i }));
expect(
await screen.findByText(
/new alias must be different from the current one/i,
),
).toBeInTheDocument();
expect(updateScanMock).not.toHaveBeenCalled();
});
it("rejects a whitespace-only edit of the current alias", async () => {
const user = userEvent.setup();
render(
<EditAliasModal
open
onOpenChange={vi.fn()}
scanId="scan-1"
currentAlias="Production audit"
/>,
);
const input = screen.getByLabelText("Alias");
await user.type(input, " ");
await user.click(screen.getByRole("button", { name: /save/i }));
expect(
await screen.findByText(
/new alias must be different from the current one/i,
),
).toBeInTheDocument();
expect(updateScanMock).not.toHaveBeenCalled();
});
it("submits the new alias as scanName", async () => {
const user = userEvent.setup();
const onOpenChange = vi.fn();
render(
<EditAliasModal
open
onOpenChange={onOpenChange}
scanId="scan-1"
currentAlias="Old name"
/>,
);
const input = screen.getByLabelText("Alias");
await user.clear(input);
await user.type(input, "Brand new name");
await user.click(screen.getByRole("button", { name: /save/i }));
await waitFor(() => expect(updateScanMock).toHaveBeenCalled());
const formData = updateScanMock.mock.calls[0][0] as FormData;
expect(formData.get("scanId")).toBe("scan-1");
expect(formData.get("scanName")).toBe("Brand new name");
expect(toastMock).toHaveBeenCalled();
expect(onOpenChange).toHaveBeenCalledWith(false);
});
it("accepts aliases up to the API limit of 100 characters", async () => {
const user = userEvent.setup();
const alias = "a".repeat(100);
render(
<EditAliasModal
open
onOpenChange={vi.fn()}
scanId="scan-1"
currentAlias="Old name"
/>,
);
const input = screen.getByLabelText("Alias");
await user.clear(input);
await user.type(input, alias);
await user.click(screen.getByRole("button", { name: /save/i }));
await waitFor(() => expect(updateScanMock).toHaveBeenCalled());
const formData = updateScanMock.mock.calls[0][0] as FormData;
expect(formData.get("scanName")).toBe(alias);
});
it("rejects aliases over the API limit of 100 characters", async () => {
const user = userEvent.setup();
render(
<EditAliasModal
open
onOpenChange={vi.fn()}
scanId="scan-1"
currentAlias="Old name"
/>,
);
const input = screen.getByLabelText("Alias");
await user.clear(input);
await user.type(input, "a".repeat(101));
await user.click(screen.getByRole("button", { name: /save/i }));
expect(
await screen.findByText(/alias must not exceed 100 characters/i),
).toBeInTheDocument();
expect(updateScanMock).not.toHaveBeenCalled();
});
it("surfaces server-side errors on the alias field", async () => {
const user = userEvent.setup();
updateScanMock.mockResolvedValueOnce({
errors: [{ detail: "Alias already in use" }],
});
render(
<EditAliasModal
open
onOpenChange={vi.fn()}
scanId="scan-1"
currentAlias="Old name"
/>,
);
const input = screen.getByLabelText("Alias");
await user.clear(input);
await user.type(input, "Conflicting");
await user.click(screen.getByRole("button", { name: /save/i }));
expect(await screen.findByText("Alias already in use")).toBeInTheDocument();
});
});