Files
cosmos-explorer/src/Explorer/ContainerCopy/CreateCopyJob/Screens/CreateCopyJobScreens.test.tsx
BChoudhury-ms a714ef02c0 Added comprehensive unit test coverage for Container Copy jobs (#2275)
* copy job uts

* unit test coverage

* lint fix

* normalize account dropdown id
2025-12-09 09:35:58 +05:30

427 lines
14 KiB
TypeScript

import "@testing-library/jest-dom";
import { fireEvent, render, screen } from "@testing-library/react";
import React from "react";
import CreateCopyJobScreens from "./CreateCopyJobScreens";
jest.mock("../../Context/CopyJobContext", () => ({
useCopyJobContext: jest.fn(),
}));
jest.mock("../Utils/useCopyJobNavigation", () => ({
useCopyJobNavigation: jest.fn(),
}));
jest.mock("./Components/NavigationControls", () => {
const MockedNavigationControls = ({
primaryBtnText,
onPrimary,
onPrevious,
onCancel,
isPrimaryDisabled,
isPreviousDisabled,
}: {
primaryBtnText: string;
onPrimary: () => void;
onPrevious: () => void;
onCancel: () => void;
isPrimaryDisabled: boolean;
isPreviousDisabled: boolean;
}) => (
<div data-testid="navigation-controls">
<button data-testid="primary-button" onClick={onPrimary} disabled={isPrimaryDisabled}>
{primaryBtnText}
</button>
<button data-testid="previous-button" onClick={onPrevious} disabled={isPreviousDisabled}>
Previous
</button>
<button data-testid="cancel-button" onClick={onCancel}>
Cancel
</button>
</div>
);
return MockedNavigationControls;
});
import { useCopyJobContext } from "../../Context/CopyJobContext";
import { useCopyJobNavigation } from "../Utils/useCopyJobNavigation";
const createMockNavigationHook = (overrides = {}) => ({
currentScreen: {
key: "SelectAccount",
component: <div data-testid="mock-screen">Mock Screen Component</div>,
},
isPrimaryDisabled: false,
isPreviousDisabled: true,
handlePrimary: jest.fn(),
handlePrevious: jest.fn(),
handleCancel: jest.fn(),
primaryBtnText: "Next",
showAddCollectionPanel: jest.fn(),
...overrides,
});
const createMockContext = (overrides = {}) => ({
contextError: "",
setContextError: jest.fn(),
copyJobState: {},
setCopyJobState: jest.fn(),
flow: {},
setFlow: jest.fn(),
resetCopyJobState: jest.fn(),
explorer: {},
...overrides,
});
describe("CreateCopyJobScreens", () => {
const mockNavigationHook = createMockNavigationHook();
const mockContext = createMockContext();
beforeEach(() => {
jest.clearAllMocks();
(useCopyJobNavigation as jest.Mock).mockReturnValue(mockNavigationHook);
(useCopyJobContext as jest.Mock).mockReturnValue(mockContext);
});
describe("Rendering", () => {
test("should render without error", () => {
render(<CreateCopyJobScreens />);
expect(screen.getByTestId("mock-screen")).toBeInTheDocument();
expect(screen.getByTestId("navigation-controls")).toBeInTheDocument();
});
test("should render current screen component", () => {
const customScreen = <div data-testid="custom-screen">Custom Screen Content</div>;
(useCopyJobNavigation as jest.Mock).mockReturnValue(
createMockNavigationHook({
currentScreen: { component: customScreen },
}),
);
render(<CreateCopyJobScreens />);
expect(screen.getByTestId("custom-screen")).toBeInTheDocument();
expect(screen.getByText("Custom Screen Content")).toBeInTheDocument();
});
test("should have correct CSS classes", () => {
const { container } = render(<CreateCopyJobScreens />);
const mainContainer = container.querySelector(".createCopyJobScreensContainer");
const contentContainer = container.querySelector(".createCopyJobScreensContent");
const footerContainer = container.querySelector(".createCopyJobScreensFooter");
expect(mainContainer).toBeInTheDocument();
expect(contentContainer).toBeInTheDocument();
expect(footerContainer).toBeInTheDocument();
});
});
describe("Error Message Bar", () => {
test("should not show error message bar when no error", () => {
render(<CreateCopyJobScreens />);
expect(screen.queryByRole("region")).not.toBeInTheDocument();
});
test("should show error message bar when context error exists", () => {
const errorMessage = "Something went wrong";
(useCopyJobContext as jest.Mock).mockReturnValue(
createMockContext({
contextError: errorMessage,
}),
);
render(<CreateCopyJobScreens />);
const messageBar = screen.getByRole("region");
expect(messageBar).toBeInTheDocument();
expect(messageBar).toHaveClass("createCopyJobErrorMessageBar");
});
test("should have correct error message bar properties", () => {
const errorMessage = "Test error message";
(useCopyJobContext as jest.Mock).mockReturnValue(
createMockContext({
contextError: errorMessage,
}),
);
render(<CreateCopyJobScreens />);
const messageBar = screen.getByRole("region");
expect(messageBar).toHaveClass("createCopyJobErrorMessageBar");
});
test("should call setContextError when dismiss button is clicked", () => {
const mockSetContextError = jest.fn();
(useCopyJobContext as jest.Mock).mockReturnValue(
createMockContext({
contextError: "Test error",
setContextError: mockSetContextError,
}),
);
render(<CreateCopyJobScreens />);
const dismissButton = screen.getByLabelText("Close");
fireEvent.click(dismissButton);
expect(mockSetContextError).toHaveBeenCalledWith(null);
});
test("should show overflow button with correct aria label", () => {
(useCopyJobContext as jest.Mock).mockReturnValue(
createMockContext({
contextError: "A very long error message that should trigger overflow behavior",
}),
);
render(<CreateCopyJobScreens />);
const overflowButton = screen.getByLabelText("See more");
expect(overflowButton).toBeInTheDocument();
});
});
describe("Navigation Controls Integration", () => {
test("should pass correct props to NavigationControls", () => {
const mockHook = createMockNavigationHook({
primaryBtnText: "Create",
isPrimaryDisabled: true,
isPreviousDisabled: false,
});
(useCopyJobNavigation as jest.Mock).mockReturnValue(mockHook);
render(<CreateCopyJobScreens />);
const primaryButton = screen.getByTestId("primary-button");
const previousButton = screen.getByTestId("previous-button");
expect(primaryButton).toHaveTextContent("Create");
expect(primaryButton).toBeDisabled();
expect(previousButton).not.toBeDisabled();
});
test("should call navigation handlers when buttons are clicked", () => {
const mockHandlePrimary = jest.fn();
const mockHandlePrevious = jest.fn();
const mockHandleCancel = jest.fn();
(useCopyJobNavigation as jest.Mock).mockReturnValue(
createMockNavigationHook({
handlePrimary: mockHandlePrimary,
handlePrevious: mockHandlePrevious,
handleCancel: mockHandleCancel,
isPrimaryDisabled: false,
isPreviousDisabled: false,
}),
);
render(<CreateCopyJobScreens />);
fireEvent.click(screen.getByTestId("primary-button"));
fireEvent.click(screen.getByTestId("previous-button"));
fireEvent.click(screen.getByTestId("cancel-button"));
expect(mockHandlePrimary).toHaveBeenCalledTimes(1);
expect(mockHandlePrevious).toHaveBeenCalledTimes(1);
expect(mockHandleCancel).toHaveBeenCalledTimes(1);
});
});
describe("Screen Component Props", () => {
test("should pass showAddCollectionPanel prop to screen component", () => {
const mockShowAddCollectionPanel = jest.fn();
const TestScreen = ({ showAddCollectionPanel }: { showAddCollectionPanel: () => void }) => (
<div>
<button data-testid="add-collection-btn" onClick={showAddCollectionPanel}>
Add Collection
</button>
</div>
);
(useCopyJobNavigation as jest.Mock).mockReturnValue(
createMockNavigationHook({
currentScreen: { component: <TestScreen showAddCollectionPanel={() => {}} /> },
showAddCollectionPanel: mockShowAddCollectionPanel,
}),
);
render(<CreateCopyJobScreens />);
const addButton = screen.getByTestId("add-collection-btn");
expect(addButton).toBeInTheDocument();
});
test("should handle screen component without props", () => {
const SimpleScreen = () => <div data-testid="simple-screen">Simple Screen</div>;
(useCopyJobNavigation as jest.Mock).mockReturnValue(
createMockNavigationHook({
currentScreen: { component: <SimpleScreen /> },
}),
);
expect(() => render(<CreateCopyJobScreens />)).not.toThrow();
expect(screen.getByTestId("simple-screen")).toBeInTheDocument();
});
});
describe("Layout and Structure", () => {
test("should maintain vertical layout with space-between alignment", () => {
const { container } = render(<CreateCopyJobScreens />);
const stackContainer = container.querySelector(".createCopyJobScreensContainer");
expect(stackContainer).toBeInTheDocument();
});
test("should have content area above navigation controls", () => {
const { container } = render(<CreateCopyJobScreens />);
const content = container.querySelector(".createCopyJobScreensContent");
const footer = container.querySelector(".createCopyJobScreensFooter");
expect(content).toBeInTheDocument();
expect(footer).toBeInTheDocument();
const contentIndex = Array.from(container.querySelectorAll("*")).indexOf(content!);
const footerIndex = Array.from(container.querySelectorAll("*")).indexOf(footer!);
expect(contentIndex).toBeLessThan(footerIndex);
});
});
describe("Error Scenarios", () => {
test("should handle missing current screen gracefully", () => {
(useCopyJobNavigation as jest.Mock).mockReturnValue(
createMockNavigationHook({
currentScreen: null,
}),
);
expect(() => render(<CreateCopyJobScreens />)).toThrow();
});
test("should handle missing screen component", () => {
(useCopyJobNavigation as jest.Mock).mockReturnValue(
createMockNavigationHook({
currentScreen: { key: "test", component: null },
}),
);
expect(() => render(<CreateCopyJobScreens />)).toThrow();
});
test("should render with valid screen component", () => {
(useCopyJobNavigation as jest.Mock).mockReturnValue(
createMockNavigationHook({
currentScreen: {
key: "test",
component: <div data-testid="valid-screen">Valid Screen</div>,
},
}),
);
expect(() => render(<CreateCopyJobScreens />)).not.toThrow();
expect(screen.getByTestId("valid-screen")).toBeInTheDocument();
});
test("should handle context hook throwing error", () => {
(useCopyJobContext as jest.Mock).mockImplementation(() => {
throw new Error("Context not available");
});
expect(() => render(<CreateCopyJobScreens />)).toThrow("Context not available");
});
test("should handle navigation hook throwing error", () => {
(useCopyJobNavigation as jest.Mock).mockImplementation(() => {
throw new Error("Navigation not available");
});
expect(() => render(<CreateCopyJobScreens />)).toThrow("Navigation not available");
});
});
describe("Multiple Error States", () => {
test("should handle error message changes", () => {
const mockSetContextError = jest.fn();
const { rerender } = render(<CreateCopyJobScreens />);
expect(screen.queryByRole("region")).not.toBeInTheDocument();
(useCopyJobContext as jest.Mock).mockReturnValue(
createMockContext({
contextError: "First error",
setContextError: mockSetContextError,
}),
);
rerender(<CreateCopyJobScreens />);
expect(screen.getByRole("region")).toBeInTheDocument();
(useCopyJobContext as jest.Mock).mockReturnValue(
createMockContext({
contextError: "Second error",
setContextError: mockSetContextError,
}),
);
rerender(<CreateCopyJobScreens />);
expect(screen.getByRole("region")).toBeInTheDocument();
(useCopyJobContext as jest.Mock).mockReturnValue(
createMockContext({
contextError: null,
setContextError: mockSetContextError,
}),
);
rerender(<CreateCopyJobScreens />);
expect(screen.queryByRole("region")).not.toBeInTheDocument();
});
});
describe("Accessibility", () => {
test("should have proper ARIA labels for message bar", () => {
(useCopyJobContext as jest.Mock).mockReturnValue(
createMockContext({
contextError: "Test error",
}),
);
render(<CreateCopyJobScreens />);
const dismissButton = screen.getByLabelText("Close");
const overflowButton = screen.getByLabelText("See more");
expect(dismissButton).toBeInTheDocument();
expect(overflowButton).toBeInTheDocument();
});
test("should have proper region role for message bar", () => {
(useCopyJobContext as jest.Mock).mockReturnValue(
createMockContext({
contextError: "Test error",
}),
);
render(<CreateCopyJobScreens />);
const messageRegion = screen.getByRole("region");
expect(messageRegion).toBeInTheDocument();
const alert = screen.getByRole("alert");
expect(alert).toBeInTheDocument();
});
});
describe("Component Integration", () => {
test("should integrate with both context and navigation hooks", () => {
const mockContext = createMockContext({
contextError: "Integration test error",
});
const mockNavigation = createMockNavigationHook({
primaryBtnText: "Integration Test",
isPrimaryDisabled: true,
});
(useCopyJobContext as jest.Mock).mockReturnValue(mockContext);
(useCopyJobNavigation as jest.Mock).mockReturnValue(mockNavigation);
render(<CreateCopyJobScreens />);
expect(screen.getByRole("region")).toBeInTheDocument();
expect(screen.getByText("Integration Test")).toBeInTheDocument();
});
});
});