mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-04 02:04:06 +00:00
fix(ui): show API error message when mute rule creation fails (#12853)
This commit is contained in:
@@ -0,0 +1,87 @@
|
|||||||
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const { fetchMock, getAuthHeadersMock, revalidatePathMock } = vi.hoisted(
|
||||||
|
() => ({
|
||||||
|
fetchMock: vi.fn(),
|
||||||
|
getAuthHeadersMock: vi.fn(),
|
||||||
|
revalidatePathMock: vi.fn(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
vi.mock("@/lib/helper", () => ({
|
||||||
|
apiBaseUrl: "https://api.test/api/v1",
|
||||||
|
getAuthHeaders: getAuthHeadersMock,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("next/cache", () => ({
|
||||||
|
revalidatePath: revalidatePathMock,
|
||||||
|
}));
|
||||||
|
|
||||||
|
import { createMuteRule } from "./mute-rules";
|
||||||
|
|
||||||
|
const NAME_CONFLICT_DETAIL = "A mute rule with this name already exists.";
|
||||||
|
|
||||||
|
const errorResponse = (contentType: string, body: string, status = 400) =>
|
||||||
|
new Response(body, {
|
||||||
|
status,
|
||||||
|
headers: { "Content-Type": contentType },
|
||||||
|
});
|
||||||
|
|
||||||
|
const nameConflictBody = JSON.stringify({
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
detail: NAME_CONFLICT_DETAIL,
|
||||||
|
status: "400",
|
||||||
|
source: { pointer: "/data/attributes/name" },
|
||||||
|
code: "invalid",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const muteRuleFormData = () => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.set("name", "Root account has a hardware MFA device enabled");
|
||||||
|
formData.set("reason", "Not our approach here with SSO");
|
||||||
|
formData.set("finding_ids", JSON.stringify(["finding-1"]));
|
||||||
|
return formData;
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
vi.stubGlobal("fetch", fetchMock);
|
||||||
|
vi.spyOn(console, "error").mockImplementation(() => {});
|
||||||
|
getAuthHeadersMock.mockResolvedValue({ Authorization: "Bearer token" });
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("createMuteRule", () => {
|
||||||
|
it("should return only the error detail for a JSON:API error response", async () => {
|
||||||
|
fetchMock.mockResolvedValue(
|
||||||
|
errorResponse("application/vnd.api+json", nameConflictBody),
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await createMuteRule(null, muteRuleFormData());
|
||||||
|
|
||||||
|
expect(result?.errors?.general).toBe(NAME_CONFLICT_DETAIL);
|
||||||
|
expect(revalidatePathMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return only the error detail for a plain JSON error response", async () => {
|
||||||
|
fetchMock.mockResolvedValue(
|
||||||
|
errorResponse("application/json", nameConflictBody),
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await createMuteRule(null, muteRuleFormData());
|
||||||
|
|
||||||
|
expect(result?.errors?.general).toBe(NAME_CONFLICT_DETAIL);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return the response text for a non-JSON error response", async () => {
|
||||||
|
fetchMock.mockResolvedValue(
|
||||||
|
errorResponse("text/plain", "Bad gateway", 502),
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await createMuteRule(null, muteRuleFormData());
|
||||||
|
|
||||||
|
expect(result?.errors?.general).toBe("Bad gateway");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -156,7 +156,8 @@ export const createMuteRule = async (
|
|||||||
let errorMessage = `Failed to create mute rule: ${response.statusText}`;
|
let errorMessage = `Failed to create mute rule: ${response.statusText}`;
|
||||||
const responseContentType = response.headers.get("content-type");
|
const responseContentType = response.headers.get("content-type");
|
||||||
try {
|
try {
|
||||||
if (responseContentType?.includes("application/json")) {
|
// The API answers with application/vnd.api+json
|
||||||
|
if (responseContentType?.includes("json")) {
|
||||||
const errorData = await response.json();
|
const errorData = await response.json();
|
||||||
const jsonApiError = (
|
const jsonApiError = (
|
||||||
errorData as {
|
errorData as {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
Mute rule creation errors show the API error message instead of the raw JSON:API response body
|
||||||
Reference in New Issue
Block a user