Added finally block and tests

This commit is contained in:
Victor Santos
2025-06-24 06:58:14 -03:00
parent 8fbff5cdc5
commit b894587a20
2 changed files with 269 additions and 2 deletions

View File

@@ -1,9 +1,16 @@
// Import the actions to access mocked functions
import { deleteSurveyAction } from "@/modules/survey/list/actions";
import { TSurvey } from "@/modules/survey/list/types/surveys";
import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
import { userEvent } from "@testing-library/user-event";
import { afterEach, describe, expect, test, vi } from "vitest";
import toast from "react-hot-toast";
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
import { SurveyDropDownMenu } from "./survey-dropdown-menu";
// Cast to mocked functions
const mockDeleteSurveyAction = vi.mocked(deleteSurveyAction);
const mockToast = vi.mocked(toast);
// Mock translation
vi.mock("@tolgee/react", () => ({
useTranslate: () => ({ t: (key: string) => key }),
@@ -43,6 +50,24 @@ vi.mock("@/modules/survey/list/actions", () => ({
getSurveyAction: vi.fn(() =>
Promise.resolve({ data: { id: "duplicatedSurveyId", name: "Duplicated Survey" } })
),
deleteSurveyAction: vi.fn(),
}));
// Mock next/navigation
const mockRouterRefresh = vi.fn();
vi.mock("next/navigation", () => ({
useRouter: () => ({
refresh: mockRouterRefresh,
push: vi.fn(),
}),
}));
// Mock react-hot-toast
vi.mock("react-hot-toast", () => ({
default: {
success: vi.fn(),
error: vi.fn(),
},
}));
describe("SurveyDropDownMenu", () => {
@@ -240,4 +265,245 @@ describe("SurveyDropDownMenu", () => {
expect(mockDuplicateSurvey).toHaveBeenCalled();
});
});
describe("handleDeleteSurvey", () => {
beforeEach(() => {
vi.clearAllMocks();
});
test("successfully deletes survey - calls all expected functions and shows success toast", async () => {
const mockDeleteSurvey = vi.fn();
mockDeleteSurveyAction.mockResolvedValueOnce({ data: true });
render(
<SurveyDropDownMenu
environmentId="env123"
survey={fakeSurvey}
publicDomain="http://survey.test"
refreshSingleUseId={vi.fn()}
duplicateSurvey={vi.fn()}
deleteSurvey={mockDeleteSurvey}
/>
);
// Open dropdown and click delete
const menuWrapper = screen.getByTestId("survey-dropdown-menu");
const triggerElement = menuWrapper.querySelector("[class*='p-2']") as HTMLElement;
await userEvent.click(triggerElement);
const deleteButton = screen.getByText("common.delete");
await userEvent.click(deleteButton);
// Confirm deletion in dialog
const confirmDeleteButton = screen.getByText("common.delete");
await userEvent.click(confirmDeleteButton);
await waitFor(() => {
expect(mockDeleteSurveyAction).toHaveBeenCalledWith({ surveyId: "testSurvey" });
expect(mockDeleteSurvey).toHaveBeenCalledWith("testSurvey");
expect(mockToast.success).toHaveBeenCalledWith("environments.surveys.survey_deleted_successfully");
expect(mockRouterRefresh).toHaveBeenCalled();
});
});
test("handles deletion error - shows error toast and resets loading state", async () => {
const mockDeleteSurvey = vi.fn();
const deletionError = new Error("Deletion failed");
mockDeleteSurveyAction.mockRejectedValueOnce(deletionError);
render(
<SurveyDropDownMenu
environmentId="env123"
survey={fakeSurvey}
publicDomain="http://survey.test"
refreshSingleUseId={vi.fn()}
duplicateSurvey={vi.fn()}
deleteSurvey={mockDeleteSurvey}
/>
);
// Open dropdown and click delete
const menuWrapper = screen.getByTestId("survey-dropdown-menu");
const triggerElement = menuWrapper.querySelector("[class*='p-2']") as HTMLElement;
await userEvent.click(triggerElement);
const deleteButton = screen.getByText("common.delete");
await userEvent.click(deleteButton);
// Confirm deletion in dialog
const confirmDeleteButton = screen.getByText("common.delete");
await userEvent.click(confirmDeleteButton);
await waitFor(() => {
expect(mockDeleteSurveyAction).toHaveBeenCalledWith({ surveyId: "testSurvey" });
expect(mockDeleteSurvey).not.toHaveBeenCalled();
expect(mockToast.error).toHaveBeenCalledWith("environments.surveys.error_deleting_survey");
expect(mockRouterRefresh).not.toHaveBeenCalled();
});
});
test("manages loading state correctly during successful deletion", async () => {
const mockDeleteSurvey = vi.fn();
mockDeleteSurveyAction.mockImplementation(
() => new Promise((resolve) => setTimeout(() => resolve({ data: true }), 100))
);
render(
<SurveyDropDownMenu
environmentId="env123"
survey={fakeSurvey}
publicDomain="http://survey.test"
refreshSingleUseId={vi.fn()}
duplicateSurvey={vi.fn()}
deleteSurvey={mockDeleteSurvey}
/>
);
// Open dropdown and click delete
const menuWrapper = screen.getByTestId("survey-dropdown-menu");
const triggerElement = menuWrapper.querySelector("[class*='p-2']") as HTMLElement;
await userEvent.click(triggerElement);
const deleteButton = screen.getByText("common.delete");
await userEvent.click(deleteButton);
// Confirm deletion in dialog using a more reliable selector
const confirmDeleteButton = screen.getByText("common.delete");
await userEvent.click(confirmDeleteButton);
// Wait for the deletion process to complete
await waitFor(() => {
expect(mockDeleteSurveyAction).toHaveBeenCalled();
expect(mockDeleteSurvey).toHaveBeenCalled();
expect(mockToast.success).toHaveBeenCalled();
});
});
test("manages loading state correctly during failed deletion", async () => {
const mockDeleteSurvey = vi.fn();
mockDeleteSurveyAction.mockImplementation(
() => new Promise((_, reject) => setTimeout(() => reject(new Error("Network error")), 100))
);
render(
<SurveyDropDownMenu
environmentId="env123"
survey={fakeSurvey}
publicDomain="http://survey.test"
refreshSingleUseId={vi.fn()}
duplicateSurvey={vi.fn()}
deleteSurvey={mockDeleteSurvey}
/>
);
// Open dropdown and click delete
const menuWrapper = screen.getByTestId("survey-dropdown-menu");
const triggerElement = menuWrapper.querySelector("[class*='p-2']") as HTMLElement;
await userEvent.click(triggerElement);
const deleteButton = screen.getByText("common.delete");
await userEvent.click(deleteButton);
// Confirm deletion in dialog using a more reliable selector
const confirmDeleteButton = screen.getByText("common.delete");
await userEvent.click(confirmDeleteButton);
// Wait for the error to occur
await waitFor(() => {
expect(mockDeleteSurveyAction).toHaveBeenCalled();
expect(mockToast.error).toHaveBeenCalledWith("environments.surveys.error_deleting_survey");
});
// Verify that deleteSurvey callback was not called due to error
expect(mockDeleteSurvey).not.toHaveBeenCalled();
expect(mockRouterRefresh).not.toHaveBeenCalled();
});
test("does not call router.refresh or success toast when deleteSurveyAction throws", async () => {
const mockDeleteSurvey = vi.fn();
mockDeleteSurveyAction.mockRejectedValueOnce(new Error("API Error"));
render(
<SurveyDropDownMenu
environmentId="env123"
survey={fakeSurvey}
publicDomain="http://survey.test"
refreshSingleUseId={vi.fn()}
duplicateSurvey={vi.fn()}
deleteSurvey={mockDeleteSurvey}
/>
);
// Open dropdown and click delete
const menuWrapper = screen.getByTestId("survey-dropdown-menu");
const triggerElement = menuWrapper.querySelector("[class*='p-2']") as HTMLElement;
await userEvent.click(triggerElement);
const deleteButton = screen.getByText("common.delete");
await userEvent.click(deleteButton);
// Confirm deletion in dialog
const confirmDeleteButton = screen.getByText("common.delete");
await userEvent.click(confirmDeleteButton);
await waitFor(() => {
expect(mockDeleteSurveyAction).toHaveBeenCalled();
expect(mockToast.error).toHaveBeenCalled();
});
// Verify success-path functions are not called
expect(mockDeleteSurvey).not.toHaveBeenCalled();
expect(mockToast.success).not.toHaveBeenCalled();
expect(mockRouterRefresh).not.toHaveBeenCalled();
});
test("calls functions in correct order during successful deletion", async () => {
const mockDeleteSurvey = vi.fn();
const callOrder: string[] = [];
mockDeleteSurveyAction.mockImplementation(async () => {
callOrder.push("deleteSurveyAction");
return { data: true };
});
mockDeleteSurvey.mockImplementation(() => {
callOrder.push("deleteSurvey");
});
(mockToast.success as any).mockImplementation(() => {
callOrder.push("toast.success");
});
mockRouterRefresh.mockImplementation(() => {
callOrder.push("router.refresh");
});
render(
<SurveyDropDownMenu
environmentId="env123"
survey={fakeSurvey}
publicDomain="http://survey.test"
refreshSingleUseId={vi.fn()}
duplicateSurvey={vi.fn()}
deleteSurvey={mockDeleteSurvey}
/>
);
// Open dropdown and click delete
const menuWrapper = screen.getByTestId("survey-dropdown-menu");
const triggerElement = menuWrapper.querySelector("[class*='p-2']") as HTMLElement;
await userEvent.click(triggerElement);
const deleteButton = screen.getByText("common.delete");
await userEvent.click(deleteButton);
// Confirm deletion in dialog
const confirmDeleteButton = screen.getByText("common.delete");
await userEvent.click(confirmDeleteButton);
await waitFor(() => {
expect(callOrder).toEqual(["deleteSurveyAction", "deleteSurvey", "toast.success", "router.refresh"]);
});
});
});
});

View File

@@ -74,8 +74,9 @@ export const SurveyDropDownMenu = ({
toast.success(t("environments.surveys.survey_deleted_successfully"));
router.refresh();
} catch (error) {
setLoading(false);
toast.error(t("environments.surveys.error_deleting_survey"));
} finally {
setLoading(false);
}
};