diff --git a/src/Explorer/ContainerCopy/ContainerCopyMessages.ts b/src/Explorer/ContainerCopy/ContainerCopyMessages.ts index 27175de68..d63f0cfad 100644 --- a/src/Explorer/ContainerCopy/ContainerCopyMessages.ts +++ b/src/Explorer/ContainerCopy/ContainerCopyMessages.ts @@ -25,7 +25,18 @@ export default { subscriptionDropdownPlaceholder: "Select a subscription", sourceAccountDropdownLabel: "Account", sourceAccountDropdownPlaceholder: "Select an account", - migrationTypeCheckboxLabel: "Copy container in offline mode", + migrationTypeOptions: { + offline: { + title: "Offline mode", + description: + "Offline container copy jobs let you copy data from a source container to a destination Cosmos DB container for supported APIs. To ensure data integrity between the source and destination, we recommend stopping updates on the source container before creating the copy job. Learn more about [offline copy jobs](https://learn.microsoft.com/azure/cosmos-db/how-to-container-copy?tabs=offline-copy&pivots=api-nosql).", + }, + online: { + title: "Online mode", + description: + "Online container copy jobs let you copy data from a source container to a destination Cosmos DB NoSQL API container using the [All Versions and Delete](https://learn.microsoft.com/azure/cosmos-db/change-feed-modes?tabs=all-versions-and-deletes#all-versions-and-deletes-change-feed-mode-preview) change feed. This allows updates to continue on the source while data is copied. A brief downtime is required at the end to safely switch over client applications to the destination container. Learn more about [online copy jobs](https://learn.microsoft.com/azure/cosmos-db/container-copy?tabs=online-copy&pivots=api-nosql#getting-started).", + }, + }, // Select Source and Target Containers Screen selectSourceAndTargetContainersDescription: diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/MigrationType.test.tsx b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/MigrationType.test.tsx new file mode 100644 index 000000000..50fff3f72 --- /dev/null +++ b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/MigrationType.test.tsx @@ -0,0 +1,241 @@ +import "@testing-library/jest-dom"; +import { fireEvent, render, screen } from "@testing-library/react"; +import React from "react"; +import ContainerCopyMessages from "../../../../ContainerCopyMessages"; +import { useCopyJobContext } from "../../../../Context/CopyJobContext"; +import { CopyJobMigrationType } from "../../../../Enums/CopyJobEnums"; +import { MigrationType } from "./MigrationType"; + +jest.mock("../../../../Context/CopyJobContext", () => ({ + useCopyJobContext: jest.fn(), +})); + +describe("MigrationType", () => { + const mockSetCopyJobState = jest.fn(); + + const defaultContextValue = { + copyJobState: { + jobName: "", + migrationType: CopyJobMigrationType.Online, + source: { + subscription: null as any, + account: null as any, + databaseId: "", + containerId: "", + }, + target: { + subscriptionId: "", + account: null as any, + databaseId: "", + containerId: "", + }, + sourceReadAccessFromTarget: false, + }, + setCopyJobState: mockSetCopyJobState, + flow: { currentScreen: "selectAccount" }, + setFlow: jest.fn(), + contextError: "", + setContextError: jest.fn(), + explorer: {} as any, + resetCopyJobState: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + (useCopyJobContext as jest.Mock).mockReturnValue(defaultContextValue); + }); + + describe("Component Rendering", () => { + it("should render migration type component with radio buttons", () => { + const { container } = render(); + + expect(container.querySelector("[data-test='migration-type']")).toBeInTheDocument(); + expect(screen.getByRole("radiogroup")).toBeInTheDocument(); + + const offlineRadio = screen.getByRole("radio", { + name: ContainerCopyMessages.migrationTypeOptions.offline.title, + }); + const onlineRadio = screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title }); + + expect(offlineRadio).toBeInTheDocument(); + expect(onlineRadio).toBeInTheDocument(); + expect(container).toMatchSnapshot(); + }); + + it("should render with online mode selected by default", () => { + render(); + + const onlineRadio = screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title }); + const offlineRadio = screen.getByRole("radio", { + name: ContainerCopyMessages.migrationTypeOptions.offline.title, + }); + + expect(onlineRadio).toBeChecked(); + expect(offlineRadio).not.toBeChecked(); + }); + + it("should render with offline mode selected when state is offline", () => { + (useCopyJobContext as jest.Mock).mockReturnValue({ + ...defaultContextValue, + copyJobState: { + ...defaultContextValue.copyJobState, + migrationType: CopyJobMigrationType.Offline, + }, + }); + + render(); + + const offlineRadio = screen.getByRole("radio", { + name: ContainerCopyMessages.migrationTypeOptions.offline.title, + }); + const onlineRadio = screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title }); + + expect(offlineRadio).toBeChecked(); + expect(onlineRadio).not.toBeChecked(); + }); + }); + + describe("Descriptions and Learn More Links", () => { + it("should render online description and learn more link when online is selected", () => { + const { container } = render(); + + expect(container.querySelector("[data-test='migration-type-description-online']")).toBeInTheDocument(); + + const learnMoreLink = screen.getByRole("link", { + name: "online copy jobs", + }); + expect(learnMoreLink).toBeInTheDocument(); + expect(learnMoreLink).toHaveAttribute( + "href", + "https://learn.microsoft.com/azure/cosmos-db/container-copy?tabs=online-copy&pivots=api-nosql#getting-started", + ); + expect(learnMoreLink).toHaveAttribute("target", "_blank"); + }); + + it("should render offline description and learn more link when offline is selected", () => { + (useCopyJobContext as jest.Mock).mockReturnValue({ + ...defaultContextValue, + copyJobState: { + ...defaultContextValue.copyJobState, + migrationType: CopyJobMigrationType.Offline, + }, + }); + + const { container } = render(); + + expect(container.querySelector("[data-test='migration-type-description-offline']")).toBeInTheDocument(); + + const learnMoreLink = screen.getByRole("link", { + name: "offline copy jobs", + }); + expect(learnMoreLink).toBeInTheDocument(); + expect(learnMoreLink).toHaveAttribute( + "href", + "https://learn.microsoft.com/azure/cosmos-db/how-to-container-copy?tabs=offline-copy&pivots=api-nosql", + ); + }); + }); + + describe("User Interactions", () => { + it("should call setCopyJobState when offline radio button is clicked", () => { + render(); + + const offlineRadio = screen.getByRole("radio", { + name: ContainerCopyMessages.migrationTypeOptions.offline.title, + }); + fireEvent.click(offlineRadio); + + expect(mockSetCopyJobState).toHaveBeenCalledWith(expect.any(Function)); + + const updateFunction = mockSetCopyJobState.mock.calls[0][0]; + const result = updateFunction(defaultContextValue.copyJobState); + + expect(result).toEqual({ + ...defaultContextValue.copyJobState, + migrationType: CopyJobMigrationType.Offline, + }); + }); + + it("should call setCopyJobState when online radio button is clicked", () => { + (useCopyJobContext as jest.Mock).mockReturnValue({ + ...defaultContextValue, + copyJobState: { + ...defaultContextValue.copyJobState, + migrationType: CopyJobMigrationType.Offline, + }, + }); + + render(); + + const onlineRadio = screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title }); + fireEvent.click(onlineRadio); + + expect(mockSetCopyJobState).toHaveBeenCalledWith(expect.any(Function)); + + const updateFunction = mockSetCopyJobState.mock.calls[0][0]; + const result = updateFunction({ + ...defaultContextValue.copyJobState, + migrationType: CopyJobMigrationType.Offline, + }); + + expect(result).toEqual({ + ...defaultContextValue.copyJobState, + migrationType: CopyJobMigrationType.Online, + }); + }); + }); + + describe("Accessibility", () => { + it("should have proper ARIA attributes", () => { + render(); + + const choiceGroup = screen.getByRole("radiogroup"); + expect(choiceGroup).toBeInTheDocument(); + expect(choiceGroup).toHaveAttribute("aria-labelledby", "migrationTypeChoiceGroup"); + }); + + it("should have proper radio button labels", () => { + render(); + + expect( + screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.offline.title }), + ).toBeInTheDocument(); + expect( + screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title }), + ).toBeInTheDocument(); + }); + }); + + describe("Edge Cases", () => { + it("should handle undefined migration type gracefully", () => { + (useCopyJobContext as jest.Mock).mockReturnValue({ + ...defaultContextValue, + copyJobState: { + ...defaultContextValue.copyJobState, + migrationType: undefined, + }, + }); + + const { container } = render(); + + expect(container.querySelector("[data-test='migration-type']")).toBeInTheDocument(); + expect( + screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.offline.title }), + ).toBeInTheDocument(); + expect( + screen.getByRole("radio", { name: ContainerCopyMessages.migrationTypeOptions.online.title }), + ).toBeInTheDocument(); + }); + + it("should handle null copyJobState gracefully", () => { + (useCopyJobContext as jest.Mock).mockReturnValue({ + ...defaultContextValue, + copyJobState: null, + }); + + const { container } = render(); + + expect(container.querySelector("[data-test='migration-type']")).toBeInTheDocument(); + }); + }); +}); diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/MigrationType.tsx b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/MigrationType.tsx new file mode 100644 index 000000000..35c2d6a63 --- /dev/null +++ b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/MigrationType.tsx @@ -0,0 +1,77 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable react/display-name */ +import { ChoiceGroup, IChoiceGroupOption, Stack, Text } from "@fluentui/react"; +import MarkdownRender from "@nteract/markdown"; +import { useCopyJobContext } from "Explorer/ContainerCopy/Context/CopyJobContext"; +import React from "react"; +import ContainerCopyMessages from "../../../../ContainerCopyMessages"; +import { CopyJobMigrationType } from "../../../../Enums/CopyJobEnums"; + +interface MigrationTypeProps {} +const options: IChoiceGroupOption[] = [ + { + key: CopyJobMigrationType.Offline, + text: ContainerCopyMessages.migrationTypeOptions.offline.title, + styles: { root: { width: "33%" } }, + }, + { + key: CopyJobMigrationType.Online, + text: ContainerCopyMessages.migrationTypeOptions.online.title, + styles: { root: { width: "33%" } }, + }, +]; + +const choiceGroupStyles = { + flexContainer: { display: "flex" as const }, + root: { + selectors: { + ".ms-ChoiceField": { + color: "var(--colorNeutralForeground1)", + }, + ".ms-ChoiceField-field:hover .ms-ChoiceFieldLabel": { + color: "var(--colorNeutralForeground1)", + }, + }, + }, +}; + +export const MigrationType: React.FC = React.memo(() => { + const { copyJobState, setCopyJobState } = useCopyJobContext(); + const handleChange = (_ev?: React.FormEvent, option?: IChoiceGroupOption) => { + if (option) { + setCopyJobState((prevState) => ({ + ...prevState, + migrationType: option.key as CopyJobMigrationType, + })); + } + }; + + const selectedKey = copyJobState?.migrationType ?? ""; + const selectedKeyLowercase = selectedKey.toLowerCase() as keyof typeof ContainerCopyMessages.migrationTypeOptions; + const selectedKeyContent = ContainerCopyMessages.migrationTypeOptions[selectedKeyLowercase]; + + return ( + + + + + {selectedKeyContent && ( + + + + + + )} + + ); +}); diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/MigrationTypeCheckbox.test.tsx b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/MigrationTypeCheckbox.test.tsx deleted file mode 100644 index 67289fe39..000000000 --- a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/MigrationTypeCheckbox.test.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import "@testing-library/jest-dom"; -import { render, screen } from "@testing-library/react"; -import React from "react"; -import { MigrationTypeCheckbox } from "./MigrationTypeCheckbox"; - -describe("MigrationTypeCheckbox", () => { - const mockOnChange = jest.fn(); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - describe("Component Rendering", () => { - it("should render with default props (unchecked state)", () => { - const { container } = render(); - - expect(container.firstChild).toMatchSnapshot(); - }); - - it("should render in checked state", () => { - const { container } = render(); - - expect(container.firstChild).toMatchSnapshot(); - }); - - it("should display the correct label text", () => { - render(); - - const checkbox = screen.getByRole("checkbox"); - expect(checkbox).toBeInTheDocument(); - - const label = screen.getByText("Copy container in offline mode"); - expect(label).toBeInTheDocument(); - }); - - it("should have correct accessibility attributes when checked", () => { - render(); - - const checkbox = screen.getByRole("checkbox"); - expect(checkbox).toBeChecked(); - expect(checkbox).toHaveAttribute("checked"); - }); - }); - - describe("FluentUI Integration", () => { - it("should render FluentUI Checkbox component correctly", () => { - render(); - - const checkbox = screen.getByRole("checkbox"); - expect(checkbox).toBeInTheDocument(); - expect(checkbox).toHaveAttribute("type", "checkbox"); - }); - - it("should render FluentUI Stack component correctly", () => { - render(); - - const stackContainer = document.querySelector(".migrationTypeRow"); - expect(stackContainer).toBeInTheDocument(); - }); - - it("should apply FluentUI Stack horizontal alignment correctly", () => { - const { container } = render(); - - const stackContainer = container.querySelector(".migrationTypeRow"); - expect(stackContainer).toBeInTheDocument(); - }); - }); -}); diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/MigrationTypeCheckbox.tsx b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/MigrationTypeCheckbox.tsx deleted file mode 100644 index 4e8ae6946..000000000 --- a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/MigrationTypeCheckbox.tsx +++ /dev/null @@ -1,33 +0,0 @@ -/* eslint-disable react/prop-types */ -/* eslint-disable react/display-name */ -import { Checkbox, ICheckboxStyles, Stack } from "@fluentui/react"; -import React from "react"; -import ContainerCopyMessages from "../../../../ContainerCopyMessages"; - -interface MigrationTypeCheckboxProps { - checked: boolean; - onChange: (_ev?: React.FormEvent, checked?: boolean) => void; -} - -const checkboxStyles: ICheckboxStyles = { - text: { color: "var(--colorNeutralForeground1)" }, - checkbox: { borderColor: "var(--colorNeutralStroke1)" }, - root: { - selectors: { - ":hover .ms-Checkbox-text": { color: "var(--colorNeutralForeground1)" }, - }, - }, -}; - -export const MigrationTypeCheckbox: React.FC = React.memo(({ checked, onChange }) => { - return ( - - - - ); -}); diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/__snapshots__/MigrationType.test.tsx.snap b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/__snapshots__/MigrationType.test.tsx.snap new file mode 100644 index 000000000..1986f7540 --- /dev/null +++ b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/__snapshots__/MigrationType.test.tsx.snap @@ -0,0 +1,109 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MigrationType Component Rendering should render migration type component with radio buttons 1`] = ` +
+
+
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+
+ +
+

+ Online container copy jobs let you copy data from a source container to a destination Cosmos DB NoSQL API container using the + + All Versions and Delete + + change feed. This allows updates to continue on the source while data is copied. A brief downtime is required at the end to safely switch over client applications to the destination container. Learn more about + + online copy jobs + + . +

+
+
+
+
+
+`; diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/__snapshots__/MigrationTypeCheckbox.test.tsx.snap b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/__snapshots__/MigrationTypeCheckbox.test.tsx.snap deleted file mode 100644 index db0a71b75..000000000 --- a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/Components/__snapshots__/MigrationTypeCheckbox.test.tsx.snap +++ /dev/null @@ -1,82 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`MigrationTypeCheckbox Component Rendering should render in checked state 1`] = ` -
-
- - -
-
-`; - -exports[`MigrationTypeCheckbox Component Rendering should render with default props (unchecked state) 1`] = ` -
-
- - -
-
-`; diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/SelectAccount.test.tsx b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/SelectAccount.test.tsx index 5fb556c3c..65529338e 100644 --- a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/SelectAccount.test.tsx +++ b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/SelectAccount.test.tsx @@ -1,5 +1,5 @@ import "@testing-library/jest-dom"; -import { fireEvent, render, screen } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import React from "react"; import { useCopyJobContext } from "../../../Context/CopyJobContext"; import { CopyJobMigrationType } from "../../../Enums/CopyJobEnums"; @@ -18,19 +18,8 @@ jest.mock("./Components/AccountDropdown", () => ({ AccountDropdown: jest.fn(() =>
Account Dropdown
), })); -jest.mock("./Components/MigrationTypeCheckbox", () => ({ - MigrationTypeCheckbox: jest.fn(({ checked, onChange }: { checked: boolean; onChange: () => void }) => ( -
- - Copy container in offline mode -
- )), +jest.mock("./Components/MigrationType", () => ({ + MigrationType: jest.fn(() =>
Migration Type
), })); describe("SelectAccount", () => { @@ -83,7 +72,7 @@ describe("SelectAccount", () => { expect(screen.getByTestId("subscription-dropdown")).toBeInTheDocument(); expect(screen.getByTestId("account-dropdown")).toBeInTheDocument(); - expect(screen.getByTestId("migration-type-checkbox")).toBeInTheDocument(); + expect(screen.getByTestId("migration-type")).toBeInTheDocument(); }); it("should render correctly with snapshot", () => { @@ -93,78 +82,20 @@ describe("SelectAccount", () => { }); describe("Migration Type Functionality", () => { - it("should display migration type checkbox as unchecked when migrationType is Online", () => { - (useCopyJobContext as jest.Mock).mockReturnValue({ - ...defaultContextValue, - copyJobState: { - ...defaultContextValue.copyJobState, - migrationType: CopyJobMigrationType.Online, - }, - }); - + it("should render migration type component", () => { render(); - const checkbox = screen.getByTestId("migration-checkbox-input"); - expect(checkbox).not.toBeChecked(); - }); - - it("should display migration type checkbox as checked when migrationType is Offline", () => { - (useCopyJobContext as jest.Mock).mockReturnValue({ - ...defaultContextValue, - copyJobState: { - ...defaultContextValue.copyJobState, - migrationType: CopyJobMigrationType.Offline, - }, - }); - - render(); - - const checkbox = screen.getByTestId("migration-checkbox-input"); - expect(checkbox).toBeChecked(); - }); - - it("should call setCopyJobState with Online migration type when checkbox is unchecked", () => { - (useCopyJobContext as jest.Mock).mockReturnValue({ - ...defaultContextValue, - copyJobState: { - ...defaultContextValue.copyJobState, - migrationType: CopyJobMigrationType.Offline, - }, - }); - - render(); - - const checkbox = screen.getByTestId("migration-checkbox-input"); - fireEvent.click(checkbox); - - expect(mockSetCopyJobState).toHaveBeenCalledWith(expect.any(Function)); - - const updateFunction = mockSetCopyJobState.mock.calls[0][0]; - const previousState = { - ...defaultContextValue.copyJobState, - migrationType: CopyJobMigrationType.Offline, - }; - const result = updateFunction(previousState); - - expect(result).toEqual({ - ...previousState, - migrationType: CopyJobMigrationType.Online, - }); + const migrationTypeComponent = screen.getByTestId("migration-type"); + expect(migrationTypeComponent).toBeInTheDocument(); }); }); describe("Performance and Optimization", () => { - it("should maintain referential equality of handler functions between renders", async () => { + it("should render without performance issues", () => { const { rerender } = render(); - - const migrationCheckbox = (await import("./Components/MigrationTypeCheckbox")).MigrationTypeCheckbox as jest.Mock; - const firstRenderHandler = migrationCheckbox.mock.calls[migrationCheckbox.mock.calls.length - 1][0].onChange; - rerender(); - const secondRenderHandler = migrationCheckbox.mock.calls[migrationCheckbox.mock.calls.length - 1][0].onChange; - - expect(firstRenderHandler).toBe(secondRenderHandler); + expect(screen.getByTestId("migration-type")).toBeInTheDocument(); }); }); }); diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/SelectAccount.tsx b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/SelectAccount.tsx index 1d7715f48..f4a0dcee3 100644 --- a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/SelectAccount.tsx +++ b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/SelectAccount.tsx @@ -1,24 +1,11 @@ import { Stack, Text } from "@fluentui/react"; import React from "react"; import ContainerCopyMessages from "../../../ContainerCopyMessages"; -import { useCopyJobContext } from "../../../Context/CopyJobContext"; -import { CopyJobMigrationType } from "../../../Enums/CopyJobEnums"; import { AccountDropdown } from "./Components/AccountDropdown"; -import { MigrationTypeCheckbox } from "./Components/MigrationTypeCheckbox"; +import { MigrationType } from "./Components/MigrationType"; import { SubscriptionDropdown } from "./Components/SubscriptionDropdown"; const SelectAccount = React.memo(() => { - const { copyJobState, setCopyJobState } = useCopyJobContext(); - - const handleMigrationTypeChange = (_ev?: React.FormEvent, checked?: boolean) => { - setCopyJobState((prevState) => ({ - ...prevState, - migrationType: checked ? CopyJobMigrationType.Offline : CopyJobMigrationType.Online, - })); - }; - - const migrationTypeChecked = copyJobState?.migrationType === CopyJobMigrationType.Offline; - return ( {ContainerCopyMessages.selectAccountDescription} @@ -27,7 +14,7 @@ const SelectAccount = React.memo(() => { - + ); }); diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/__snapshots__/SelectAccount.test.tsx.snap b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/__snapshots__/SelectAccount.test.tsx.snap index b84b677cc..0b540eba6 100644 --- a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/__snapshots__/SelectAccount.test.tsx.snap +++ b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/SelectAccount/__snapshots__/SelectAccount.test.tsx.snap @@ -21,14 +21,9 @@ exports[`SelectAccount Component Rendering should render correctly with snapshot Account Dropdown
- - Copy container in offline mode + Migration Type
`; diff --git a/src/Explorer/ContainerCopy/containerCopyStyles.less b/src/Explorer/ContainerCopy/containerCopyStyles.less index c86986c62..6f99f4055 100644 --- a/src/Explorer/ContainerCopy/containerCopyStyles.less +++ b/src/Explorer/ContainerCopy/containerCopyStyles.less @@ -138,6 +138,14 @@ color: var(--colorNeutralForeground1); } } + .migrationTypeDescription { + p { + color: var(--colorNeutralForeground1); + } + a { + color: var(--colorBrandForeground1); + } + } } .create-container-link-btn { padding: 0; @@ -181,6 +189,9 @@ background-color: var(--colorNeutralBackground3); } } + .ms-DetailsHeader-cellTitle { + padding-left: 20px; + } } .ms-DetailsRow { diff --git a/test/sql/containercopy.spec.ts b/test/sql/containercopy.spec.ts index c019b99b7..10e7c8da1 100644 --- a/test/sql/containercopy.spec.ts +++ b/test/sql/containercopy.spec.ts @@ -83,22 +83,33 @@ test.describe("Container Copy", () => { ); await accountItem.click(); - // Verifying online or offline checkbox functionality + // Verifying online or offline migration functionality /** - * This test verifies the functionality of the migration type checkbox that toggles between + * This test verifies the functionality of the migration type radio that toggles between * online and offline container copy modes. It ensures that: * 1. When online mode is selected, the user is directed to a permissions screen * 2. When offline mode is selected, the user bypasses the permissions screen * 3. The UI correctly reflects the selected migration type throughout the workflow */ - const fluentUiCheckboxContainer = panel.getByTestId("migration-type-checkbox").locator("div.ms-Checkbox"); - await fluentUiCheckboxContainer.click(); + const migrationTypeContainer = panel.getByTestId("migration-type"); + const onlineCopyRadioButton = migrationTypeContainer.getByRole("radio", { name: /Online mode/i }); + await onlineCopyRadioButton.click(); + + await expect(migrationTypeContainer.getByTestId("migration-type-description-online")).toBeVisible(); + await panel.getByRole("button", { name: "Next" }).click(); + await expect(panel.getByTestId("Panel:AssignPermissionsContainer")).toBeVisible(); await expect(panel.getByText("Online container copy", { exact: true })).toBeVisible(); await panel.getByRole("button", { name: "Previous" }).click(); - await fluentUiCheckboxContainer.click(); + + const offlineCopyRadioButton = migrationTypeContainer.getByRole("radio", { name: /Offline mode/i }); + await offlineCopyRadioButton.click(); + + await expect(migrationTypeContainer.getByTestId("migration-type-description-offline")).toBeVisible(); + await panel.getByRole("button", { name: "Next" }).click(); + await expect(panel.getByTestId("Panel:SelectSourceAndTargetContainers")).toBeVisible(); await expect(panel.getByTestId("Panel:AssignPermissionsContainer")).not.toBeVisible(); @@ -284,8 +295,9 @@ test.describe("Container Copy", () => { throw new Error("No dropdown items available after filtering"); } - const fluentUiCheckboxContainer = panel.getByTestId("migration-type-checkbox").locator("div.ms-Checkbox"); - await fluentUiCheckboxContainer.click(); + const migrationTypeContainer = panel.getByTestId("migration-type"); + const onlineCopyRadioButton = migrationTypeContainer.getByRole("radio", { name: /Online mode/i }); + await onlineCopyRadioButton.click(); await panel.getByRole("button", { name: "Next" }).click();