Files
cosmos-explorer/src/Explorer/ContainerCopy/Context/CopyJobContext.test.tsx

661 lines
19 KiB
TypeScript

import "@testing-library/jest-dom";
import { act, render, screen } from "@testing-library/react";
import React from "react";
import Explorer from "../../Explorer";
import { CopyJobMigrationType } from "../Enums/CopyJobEnums";
import CopyJobContextProvider, { CopyJobContext, useCopyJobContext } from "./CopyJobContext";
jest.mock("UserContext", () => ({
userContext: {
subscriptionId: "test-subscription-id",
databaseAccount: {
id: "/subscriptions/test-sub/resourceGroups/test-rg/providers/Microsoft.DocumentDB/databaseAccounts/test-account",
name: "test-account",
location: "East US",
kind: "GlobalDocumentDB",
},
},
}));
describe("CopyJobContext", () => {
let mockExplorer: Explorer;
beforeEach(() => {
mockExplorer = {} as Explorer;
});
afterEach(() => {
jest.clearAllMocks();
});
describe("CopyJobContextProvider", () => {
it("should render children correctly", () => {
render(
<CopyJobContextProvider explorer={mockExplorer}>
<div data-testid="test-child">Test Child</div>
</CopyJobContextProvider>,
);
expect(screen.getByTestId("test-child")).toBeInTheDocument();
expect(screen.getByTestId("test-child")).toHaveTextContent("Test Child");
});
it("should initialize with default state", () => {
let contextValue: any;
render(
<CopyJobContextProvider explorer={mockExplorer}>
<CopyJobContext.Consumer>
{(value) => {
contextValue = value;
return null;
}}
</CopyJobContext.Consumer>
</CopyJobContextProvider>,
);
expect(contextValue).toBeDefined();
expect(contextValue.copyJobState).toEqual({
jobName: "",
migrationType: CopyJobMigrationType.Offline,
source: {
subscription: null,
account: null,
databaseId: "",
containerId: "",
},
target: {
subscriptionId: "test-subscription-id",
account: {
id: "/subscriptions/test-sub/resourceGroups/test-rg/providers/Microsoft.DocumentDB/databaseAccounts/test-account",
name: "test-account",
location: "East US",
kind: "GlobalDocumentDB",
},
databaseId: "",
containerId: "",
},
sourceReadAccessFromTarget: false,
});
expect(contextValue.flow).toBeNull();
expect(contextValue.contextError).toBeNull();
expect(contextValue.explorer).toBe(mockExplorer);
});
it("should provide setCopyJobState function", () => {
let contextValue: any;
render(
<CopyJobContextProvider explorer={mockExplorer}>
<CopyJobContext.Consumer>
{(value) => {
contextValue = value;
return null;
}}
</CopyJobContext.Consumer>
</CopyJobContextProvider>,
);
expect(contextValue.setCopyJobState).toBeDefined();
expect(typeof contextValue.setCopyJobState).toBe("function");
});
it("should provide setFlow function", () => {
let contextValue: any;
render(
<CopyJobContextProvider explorer={mockExplorer}>
<CopyJobContext.Consumer>
{(value) => {
contextValue = value;
return null;
}}
</CopyJobContext.Consumer>
</CopyJobContextProvider>,
);
expect(contextValue.setFlow).toBeDefined();
expect(typeof contextValue.setFlow).toBe("function");
});
it("should provide setContextError function", () => {
let contextValue: any;
render(
<CopyJobContextProvider explorer={mockExplorer}>
<CopyJobContext.Consumer>
{(value) => {
contextValue = value;
return null;
}}
</CopyJobContext.Consumer>
</CopyJobContextProvider>,
);
expect(contextValue.setContextError).toBeDefined();
expect(typeof contextValue.setContextError).toBe("function");
});
it("should provide resetCopyJobState function", () => {
let contextValue: any;
render(
<CopyJobContextProvider explorer={mockExplorer}>
<CopyJobContext.Consumer>
{(value) => {
contextValue = value;
return null;
}}
</CopyJobContext.Consumer>
</CopyJobContextProvider>,
);
expect(contextValue.resetCopyJobState).toBeDefined();
expect(typeof contextValue.resetCopyJobState).toBe("function");
});
it("should update copyJobState when setCopyJobState is called", () => {
let contextValue: any;
const TestComponent = (): JSX.Element => {
const context = useCopyJobContext();
contextValue = context;
return (
<button
onClick={() =>
context.setCopyJobState({
...context.copyJobState,
jobName: "test-job",
migrationType: CopyJobMigrationType.Online,
})
}
>
Update Job
</button>
);
};
render(
<CopyJobContextProvider explorer={mockExplorer}>
<TestComponent />
</CopyJobContextProvider>,
);
const button = screen.getByText("Update Job");
act(() => {
button.click();
});
expect(contextValue.copyJobState.jobName).toBe("test-job");
expect(contextValue.copyJobState.migrationType).toBe(CopyJobMigrationType.Online);
});
it("should update flow when setFlow is called", () => {
let contextValue: any;
const TestComponent = (): JSX.Element => {
const context = useCopyJobContext();
contextValue = context;
const handleSetFlow = (): void => {
context.setFlow({ currentScreen: "source-selection" });
};
return <button onClick={handleSetFlow}>Set Flow</button>;
};
render(
<CopyJobContextProvider explorer={mockExplorer}>
<TestComponent />
</CopyJobContextProvider>,
);
expect(contextValue.flow).toBeNull();
const button = screen.getByText("Set Flow");
act(() => {
button.click();
});
expect(contextValue.flow).toEqual({ currentScreen: "source-selection" });
});
it("should update contextError when setContextError is called", () => {
let contextValue: any;
const TestComponent = (): JSX.Element => {
const context = useCopyJobContext();
contextValue = context;
return <button onClick={() => context.setContextError("Test error message")}>Set Error</button>;
};
render(
<CopyJobContextProvider explorer={mockExplorer}>
<TestComponent />
</CopyJobContextProvider>,
);
expect(contextValue.contextError).toBeNull();
const button = screen.getByText("Set Error");
act(() => {
button.click();
});
expect(contextValue.contextError).toBe("Test error message");
});
it("should reset copyJobState when resetCopyJobState is called", () => {
let contextValue: any;
const TestComponent = (): JSX.Element => {
const context = useCopyJobContext();
contextValue = context;
const handleUpdate = (): void => {
context.setCopyJobState({
...context.copyJobState,
jobName: "modified-job",
migrationType: CopyJobMigrationType.Online,
source: {
...context.copyJobState.source,
databaseId: "test-db",
containerId: "test-container",
},
});
};
return (
<>
<button onClick={handleUpdate}>Update</button>
<button onClick={context.resetCopyJobState}>Reset</button>
</>
);
};
render(
<CopyJobContextProvider explorer={mockExplorer}>
<TestComponent />
</CopyJobContextProvider>,
);
const updateButton = screen.getByText("Update");
act(() => {
updateButton.click();
});
expect(contextValue.copyJobState.jobName).toBe("modified-job");
expect(contextValue.copyJobState.migrationType).toBe(CopyJobMigrationType.Online);
expect(contextValue.copyJobState.source.databaseId).toBe("test-db");
const resetButton = screen.getByText("Reset");
act(() => {
resetButton.click();
});
expect(contextValue.copyJobState.jobName).toBe("");
expect(contextValue.copyJobState.migrationType).toBe(CopyJobMigrationType.Offline);
expect(contextValue.copyJobState.source.databaseId).toBe("");
expect(contextValue.copyJobState.source.containerId).toBe("");
});
it("should maintain explorer reference", () => {
let contextValue: any;
render(
<CopyJobContextProvider explorer={mockExplorer}>
<CopyJobContext.Consumer>
{(value) => {
contextValue = value;
return null;
}}
</CopyJobContext.Consumer>
</CopyJobContextProvider>,
);
expect(contextValue.explorer).toBe(mockExplorer);
});
it("should handle multiple state updates correctly", () => {
let contextValue: any;
const TestComponent = (): JSX.Element => {
const context = useCopyJobContext();
contextValue = context;
return (
<>
<button onClick={() => context.setCopyJobState({ ...context.copyJobState, jobName: "job-1" })}>
Update 1
</button>
<button onClick={() => context.setFlow({ currentScreen: "screen-1" })}>Flow 1</button>
<button onClick={() => context.setContextError("error-1")}>Error 1</button>
</>
);
};
render(
<CopyJobContextProvider explorer={mockExplorer}>
<TestComponent />
</CopyJobContextProvider>,
);
act(() => {
screen.getByText("Update 1").click();
});
expect(contextValue.copyJobState.jobName).toBe("job-1");
act(() => {
screen.getByText("Flow 1").click();
});
expect(contextValue.flow).toEqual({ currentScreen: "screen-1" });
act(() => {
screen.getByText("Error 1").click();
});
expect(contextValue.contextError).toBe("error-1");
});
it("should handle partial state updates", () => {
let contextValue: any;
const TestComponent = (): JSX.Element => {
const context = useCopyJobContext();
contextValue = context;
const handlePartialUpdate = (): void => {
context.setCopyJobState((prev) => ({
...prev,
jobName: "partial-update",
}));
};
return <button onClick={handlePartialUpdate}>Partial Update</button>;
};
render(
<CopyJobContextProvider explorer={mockExplorer}>
<TestComponent />
</CopyJobContextProvider>,
);
const initialState = { ...contextValue.copyJobState };
act(() => {
screen.getByText("Partial Update").click();
});
expect(contextValue.copyJobState.jobName).toBe("partial-update");
expect(contextValue.copyJobState.migrationType).toBe(initialState.migrationType);
expect(contextValue.copyJobState.source).toEqual(initialState.source);
expect(contextValue.copyJobState.target).toEqual(initialState.target);
});
});
describe("useCopyJobContext", () => {
it("should return context value when used within provider", () => {
let contextValue: any;
const TestComponent = (): null => {
const context = useCopyJobContext();
contextValue = context;
return null;
};
render(
<CopyJobContextProvider explorer={mockExplorer}>
<TestComponent />
</CopyJobContextProvider>,
);
expect(contextValue).toBeDefined();
expect(contextValue.copyJobState).toBeDefined();
expect(contextValue.setCopyJobState).toBeDefined();
expect(contextValue.flow).toBeNull();
expect(contextValue.setFlow).toBeDefined();
expect(contextValue.contextError).toBeNull();
expect(contextValue.setContextError).toBeDefined();
expect(contextValue.resetCopyJobState).toBeDefined();
expect(contextValue.explorer).toBe(mockExplorer);
});
it("should throw error when used outside provider", () => {
const originalError = console.error;
console.error = jest.fn();
const TestComponent = (): null => {
useCopyJobContext();
return null;
};
expect(() => {
render(<TestComponent />);
}).toThrow("useCopyJobContext must be used within a CopyJobContextProvider");
console.error = originalError;
});
it("should allow updating state through hook", () => {
let contextValue: any;
const TestComponent = (): JSX.Element => {
const context = useCopyJobContext();
contextValue = context;
return (
<button
onClick={() =>
context.setCopyJobState({
...context.copyJobState,
jobName: "hook-test-job",
})
}
>
Update
</button>
);
};
render(
<CopyJobContextProvider explorer={mockExplorer}>
<TestComponent />
</CopyJobContextProvider>,
);
act(() => {
screen.getByText("Update").click();
});
expect(contextValue.copyJobState.jobName).toBe("hook-test-job");
});
it("should allow resetting state through hook", () => {
let contextValue: any;
const TestComponent = (): JSX.Element => {
const context = useCopyJobContext();
contextValue = context;
return (
<>
<button
onClick={() =>
context.setCopyJobState({
...context.copyJobState,
jobName: "modified",
source: {
...context.copyJobState.source,
databaseId: "modified-db",
},
})
}
>
Modify
</button>
<button onClick={() => context.resetCopyJobState()}>Reset</button>
</>
);
};
render(
<CopyJobContextProvider explorer={mockExplorer}>
<TestComponent />
</CopyJobContextProvider>,
);
act(() => {
screen.getByText("Modify").click();
});
expect(contextValue.copyJobState.jobName).toBe("modified");
expect(contextValue.copyJobState.source.databaseId).toBe("modified-db");
act(() => {
screen.getByText("Reset").click();
});
expect(contextValue.copyJobState.jobName).toBe("");
expect(contextValue.copyJobState.source.databaseId).toBe("");
});
it("should maintain state consistency across multiple components", () => {
let contextValue1: any;
let contextValue2: any;
const TestComponent1 = (): JSX.Element => {
const context = useCopyJobContext();
contextValue1 = context;
return (
<button
onClick={() =>
context.setCopyJobState({
...context.copyJobState,
jobName: "shared-job",
})
}
>
Update From Component 1
</button>
);
};
const TestComponent2 = (): JSX.Element => {
const context = useCopyJobContext();
contextValue2 = context;
return <div data-testid="component-2">Component 2</div>;
};
render(
<CopyJobContextProvider explorer={mockExplorer}>
<TestComponent1 />
<TestComponent2 />
</CopyJobContextProvider>,
);
expect(contextValue1.copyJobState).toEqual(contextValue2.copyJobState);
act(() => {
screen.getByText("Update From Component 1").click();
});
expect(contextValue1.copyJobState.jobName).toBe("shared-job");
expect(contextValue2.copyJobState.jobName).toBe("shared-job");
});
});
describe("Initial State", () => {
it("should initialize with offline migration type", () => {
let contextValue: any;
render(
<CopyJobContextProvider explorer={mockExplorer}>
<CopyJobContext.Consumer>
{(value) => {
contextValue = value;
return null;
}}
</CopyJobContext.Consumer>
</CopyJobContextProvider>,
);
expect(contextValue.copyJobState.migrationType).toBe(CopyJobMigrationType.Offline);
});
it("should initialize source with userContext values", () => {
let contextValue: any;
render(
<CopyJobContextProvider explorer={mockExplorer}>
<CopyJobContext.Consumer>
{(value) => {
contextValue = value;
return null;
}}
</CopyJobContext.Consumer>
</CopyJobContextProvider>,
);
expect(contextValue.copyJobState.source?.subscription?.subscriptionId).toBeUndefined();
expect(contextValue.copyJobState.source?.account?.name).toBeUndefined();
});
it("should initialize target with userContext values", () => {
let contextValue: any;
render(
<CopyJobContextProvider explorer={mockExplorer}>
<CopyJobContext.Consumer>
{(value) => {
contextValue = value;
return null;
}}
</CopyJobContext.Consumer>
</CopyJobContextProvider>,
);
expect(contextValue.copyJobState.target.subscriptionId).toBe("test-subscription-id");
expect(contextValue.copyJobState.target.account.name).toBe("test-account");
});
it("should initialize sourceReadAccessFromTarget as false", () => {
let contextValue: any;
render(
<CopyJobContextProvider explorer={mockExplorer}>
<CopyJobContext.Consumer>
{(value) => {
contextValue = value;
return null;
}}
</CopyJobContext.Consumer>
</CopyJobContextProvider>,
);
expect(contextValue.copyJobState.sourceReadAccessFromTarget).toBe(false);
});
it("should initialize with empty database and container ids", () => {
let contextValue: any;
render(
<CopyJobContextProvider explorer={mockExplorer}>
<CopyJobContext.Consumer>
{(value) => {
contextValue = value;
return null;
}}
</CopyJobContext.Consumer>
</CopyJobContextProvider>,
);
expect(contextValue.copyJobState.source.databaseId).toBe("");
expect(contextValue.copyJobState.source.containerId).toBe("");
expect(contextValue.copyJobState.target.databaseId).toBe("");
expect(contextValue.copyJobState.target.containerId).toBe("");
});
});
});