adding tests

This commit is contained in:
yuneng-jiang
2026-01-27 23:38:23 -08:00
parent 58eca8fb28
commit c4d3750601
@@ -0,0 +1,348 @@
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { beforeEach, describe, expect, it, vi, Mock } from "vitest";
import SpendLogsSettingsModal from "./SpendLogsSettingsModal";
import { useStoreRequestInSpendLogs } from "@/app/(dashboard)/hooks/storeRequestInSpendLogs/useStoreRequestInSpendLogs";
import NotificationsManager from "@/components/molecules/notifications_manager";
import { parseErrorMessage } from "@/components/shared/errorUtils";
import { renderWithProviders } from "../../../../tests/test-utils";
vi.mock("@/app/(dashboard)/hooks/storeRequestInSpendLogs/useStoreRequestInSpendLogs");
vi.mock("@/components/molecules/notifications_manager", () => ({
default: {
success: vi.fn(),
fromBackend: vi.fn(),
},
}));
vi.mock("@/components/shared/errorUtils", () => ({
parseErrorMessage: vi.fn(),
}));
const mockUseStoreRequestInSpendLogs = vi.mocked(useStoreRequestInSpendLogs);
const mockNotificationsManager = vi.mocked(NotificationsManager);
const mockParseErrorMessage = vi.mocked(parseErrorMessage);
describe("SpendLogsSettingsModal", () => {
const mockOnCancel = vi.fn();
const mockOnSuccess = vi.fn();
const mockMutateAsync = vi.fn();
const defaultProps = {
isVisible: true,
onCancel: mockOnCancel,
onSuccess: mockOnSuccess,
};
beforeEach(() => {
vi.clearAllMocks();
mockUseStoreRequestInSpendLogs.mockReturnValue({
mutateAsync: mockMutateAsync,
isPending: false,
} as any);
mockParseErrorMessage.mockImplementation((error: any) => error?.message || String(error));
});
it("should render the modal", () => {
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
expect(screen.getByRole("dialog")).toBeInTheDocument();
expect(screen.getByText("Spend Logs Settings")).toBeInTheDocument();
});
it("should render form fields with initial values", () => {
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
expect(screen.getByText("Store Prompts in Spend Logs")).toBeInTheDocument();
expect(screen.getByLabelText("Maximum Spend Logs Retention Period (Optional)")).toBeInTheDocument();
expect(screen.getByPlaceholderText("e.g., 7d, 30d")).toBeInTheDocument();
});
it("should render cancel and save buttons", () => {
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
expect(screen.getByRole("button", { name: "Cancel" })).toBeInTheDocument();
expect(screen.getByRole("button", { name: "Save Settings" })).toBeInTheDocument();
});
it("should call onCancel when cancel button is clicked", async () => {
const user = userEvent.setup();
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const cancelButton = screen.getByRole("button", { name: "Cancel" });
await user.click(cancelButton);
expect(mockOnCancel).toHaveBeenCalledTimes(1);
});
it("should call onCancel when modal close button is clicked", async () => {
const user = userEvent.setup();
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const closeButton = screen.getByRole("button", { name: /close/i });
await user.click(closeButton);
expect(mockOnCancel).toHaveBeenCalledTimes(1);
});
it("should toggle store prompts switch", async () => {
const user = userEvent.setup();
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const switchElement = screen.getByRole("switch");
expect(switchElement).not.toBeChecked();
await user.click(switchElement);
await waitFor(() => {
expect(switchElement).toBeChecked();
});
});
it("should update retention period input", async () => {
const user = userEvent.setup();
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const retentionInput = screen.getByPlaceholderText("e.g., 7d, 30d");
await user.type(retentionInput, "30d");
expect(retentionInput).toHaveValue("30d");
});
it("should submit form with store prompts enabled and retention period", async () => {
const user = userEvent.setup();
mockMutateAsync.mockImplementation(async (params, options) => {
await Promise.resolve();
options?.onSuccess?.();
return { message: "Success" };
});
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const switchElement = screen.getByRole("switch");
await user.click(switchElement);
const retentionInput = screen.getByPlaceholderText("e.g., 7d, 30d");
await user.type(retentionInput, "30d");
const saveButton = screen.getByRole("button", { name: "Save Settings" });
await user.click(saveButton);
await waitFor(() => {
expect(mockMutateAsync).toHaveBeenCalledWith(
{
store_prompts_in_spend_logs: true,
maximum_spend_logs_retention_period: "30d",
},
expect.any(Object)
);
});
});
it("should submit form with store prompts disabled and no retention period", async () => {
const user = userEvent.setup();
mockMutateAsync.mockImplementation(async (params, options) => {
await Promise.resolve();
options?.onSuccess?.();
return { message: "Success" };
});
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const saveButton = screen.getByRole("button", { name: "Save Settings" });
await user.click(saveButton);
await waitFor(() => {
expect(mockMutateAsync).toHaveBeenCalledWith(
{
store_prompts_in_spend_logs: false,
maximum_spend_logs_retention_period: undefined,
},
expect.any(Object)
);
});
});
it("should show success notification and call onSuccess on successful submission", async () => {
const user = userEvent.setup();
mockMutateAsync.mockImplementation(async (params, options) => {
await Promise.resolve();
options?.onSuccess?.();
return { message: "Success" };
});
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const saveButton = screen.getByRole("button", { name: "Save Settings" });
await user.click(saveButton);
await waitFor(() => {
expect(mockNotificationsManager.success).toHaveBeenCalledWith("Spend logs settings updated successfully");
expect(mockOnSuccess).toHaveBeenCalledTimes(1);
});
});
it("should show error notification when submission fails", async () => {
const user = userEvent.setup();
const error = new Error("Network error");
mockMutateAsync.mockRejectedValue(error);
mockParseErrorMessage.mockReturnValue("Network error");
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const saveButton = screen.getByRole("button", { name: "Save Settings" });
await user.click(saveButton);
await waitFor(() => {
expect(mockNotificationsManager.fromBackend).toHaveBeenCalledWith("Failed to save spend logs settings: Network error");
});
});
it("should show error notification from onError callback", async () => {
const user = userEvent.setup();
const error = new Error("Backend error");
mockMutateAsync.mockImplementation((params, options) => {
options?.onError?.(error);
return Promise.reject(error);
});
mockParseErrorMessage.mockReturnValue("Backend error");
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const saveButton = screen.getByRole("button", { name: "Save Settings" });
await user.click(saveButton);
await waitFor(() => {
expect(mockNotificationsManager.fromBackend).toHaveBeenCalledWith("Failed to save spend logs settings: Backend error");
});
});
it("should disable cancel button when pending", () => {
mockUseStoreRequestInSpendLogs.mockReturnValue({
mutateAsync: mockMutateAsync,
isPending: true,
} as any);
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const cancelButton = screen.getByRole("button", { name: "Cancel" });
expect(cancelButton).toBeDisabled();
});
it("should show loading state on save button when pending", () => {
mockUseStoreRequestInSpendLogs.mockReturnValue({
mutateAsync: mockMutateAsync,
isPending: true,
} as any);
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const saveButton = screen.getByRole("button", { name: /Saving/i });
expect(saveButton).toBeInTheDocument();
expect(saveButton.className).toContain("ant-btn-loading");
});
it("should call onCancel when cancel button is clicked after modifying form", async () => {
const user = userEvent.setup();
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const switchElement = screen.getByRole("switch");
await user.click(switchElement);
const retentionInput = screen.getByPlaceholderText("e.g., 7d, 30d");
await user.type(retentionInput, "30d");
expect(switchElement).toBeChecked();
expect(retentionInput).toHaveValue("30d");
const cancelButton = screen.getByRole("button", { name: "Cancel" });
await user.click(cancelButton);
expect(mockOnCancel).toHaveBeenCalledTimes(1);
});
it("should reset form fields after successful submission", async () => {
const user = userEvent.setup();
mockMutateAsync.mockImplementation(async (params, options) => {
await Promise.resolve();
options?.onSuccess?.();
return { message: "Success" };
});
const { rerender } = renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const switchElement = screen.getByRole("switch");
await user.click(switchElement);
const retentionInput = screen.getByPlaceholderText("e.g., 7d, 30d");
await user.type(retentionInput, "30d");
expect(switchElement).toBeChecked();
expect(retentionInput).toHaveValue("30d");
const saveButton = screen.getByRole("button", { name: "Save Settings" });
await user.click(saveButton);
await waitFor(() => {
expect(mockNotificationsManager.success).toHaveBeenCalled();
});
rerender(<SpendLogsSettingsModal {...defaultProps} />);
await waitFor(() => {
const updatedSwitchElement = screen.getByRole("switch");
const updatedRetentionInput = screen.getByPlaceholderText("e.g., 7d, 30d");
expect(updatedSwitchElement).not.toBeChecked();
expect(updatedRetentionInput).toHaveValue("");
});
});
it("should not call onSuccess when it is not provided", async () => {
const user = userEvent.setup();
mockMutateAsync.mockImplementation(async (params, options) => {
await Promise.resolve();
options?.onSuccess?.();
return { message: "Success" };
});
renderWithProviders(<SpendLogsSettingsModal isVisible={true} onCancel={mockOnCancel} />);
const saveButton = screen.getByRole("button", { name: "Save Settings" });
await user.click(saveButton);
await waitFor(() => {
expect(mockNotificationsManager.success).toHaveBeenCalled();
});
});
it("should not render modal when isVisible is false", () => {
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} isVisible={false} />);
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
});
it("should submit form with only store prompts enabled and no retention period", async () => {
const user = userEvent.setup();
mockMutateAsync.mockImplementation(async (params, options) => {
await Promise.resolve();
options?.onSuccess?.();
return { message: "Success" };
});
renderWithProviders(<SpendLogsSettingsModal {...defaultProps} />);
const switchElement = screen.getByRole("switch");
await user.click(switchElement);
const saveButton = screen.getByRole("button", { name: "Save Settings" });
await user.click(saveButton);
await waitFor(() => {
expect(mockMutateAsync).toHaveBeenCalledWith(
{
store_prompts_in_spend_logs: true,
maximum_spend_logs_retention_period: undefined,
},
expect.any(Object)
);
});
});
});