Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f8128b8
feat: create GlobalContent.
crhallberg Feb 7, 2023
186bf23
refactor: apply GlobalContext.
crhallberg Feb 7, 2023
454a2cc
refactor: remove unused mock context.
crhallberg Feb 7, 2023
7dc0c55
feat: begin to move modal control to GlobalContext.
crhallberg Feb 8, 2023
c2463eb
feat: add theme switcher to GlobalContext.
crhallberg Feb 8, 2023
d5a3433
fix: StateModal and modal closing behavior.
demiankatz Feb 9, 2023
6492d60
revert: move theme functionality to dark-theme branch.
crhallberg Feb 14, 2023
02aa1b1
types: fix GlobalState.
crhallberg Feb 14, 2023
73a58d9
mix: GlobalContext feedback 1 (no tests).
crhallberg Feb 15, 2023
807ab0e
refactor: isModalOpen to function. Fixed state update code.
crhallberg Feb 17, 2023
b263b9a
Merge remote-tracking branch 'origin/dev' into global-context
crhallberg May 23, 2023
631d2cb
feat: add GlobalContext to entire app.
crhallberg May 23, 2023
c4de584
fix: ParentsModal now opens and closes and verb and verb.
crhallberg May 23, 2023
b70f0e4
fix: explicitly handle undefined.
crhallberg May 23, 2023
70c484e
fix: modal integration updates
demiankatz May 23, 2023
af162ec
Fix broken tests.
demiankatz May 23, 2023
3d42d10
lint.
demiankatz May 23, 2023
b9b8d5f
Merge branch 'dev' into global-context
demiankatz Oct 24, 2023
7b96688
Merge branch 'dev' into global-context
demiankatz Oct 31, 2023
aa82e27
Merge branch 'dev' into global-context
demiankatz Jul 1, 2024
d19afc7
Remove references to deleted toggle function; improve tests.
demiankatz Jul 1, 2024
62ade0b
Review feedback.
demiankatz Jul 1, 2024
72f6c17
Merge branch 'dev' into global-context
demiankatz Jul 1, 2024
c0a1f6b
improve types
demiankatz Jul 1, 2024
4deddea
simplify useContext
demiankatz Jul 1, 2024
9cacdea
fix: return limited state.
Jul 3, 2024
fb2d027
Merge branch 'dev' into global-context
demiankatz Jul 5, 2024
f48b273
Use open/close instead of toggle.
demiankatz Jul 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions client/components/edit/EditParentsButton.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,31 @@ jest.mock("../../context/EditorContext", () => ({
},
}));

const mockUseGlobalContext = jest.fn();
jest.mock("../../context/GlobalContext", () => ({
useGlobalContext: () => {
return mockUseGlobalContext();
},
}));

describe("EditParentsButton", () => {
let editorValues;
let globalValues;
let pid: string;
beforeEach(() => {
pid = "foo:123";
editorValues = {
action: {
setParentsModalActivePid: jest.fn(),
toggleParentsModal: jest.fn(),
},
};
mockUseEditorContext.mockReturnValue(editorValues);
globalValues = {
action: {
openModal: jest.fn(),
},
};
mockUseGlobalContext.mockReturnValue(globalValues);
});

it("renders", () => {
Expand All @@ -36,6 +49,6 @@ describe("EditParentsButton", () => {
await userEvent.setup().click(screen.getByRole("button"));

expect(editorValues.action.setParentsModalActivePid).toHaveBeenCalledWith(pid);
expect(editorValues.action.toggleParentsModal).toHaveBeenCalled();
expect(globalValues.action.openModal).toHaveBeenCalledWith("parents");
});
});
9 changes: 7 additions & 2 deletions client/components/edit/EditParentsButton.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from "react";
import { useGlobalContext } from "../../context/GlobalContext";
import { useEditorContext } from "../../context/EditorContext";

export interface ObjectStatusProps {
Expand All @@ -7,12 +8,16 @@ export interface ObjectStatusProps {

export const EditParentsButton = ({ pid }: ObjectStatusProps): React.ReactElement => {
const {
action: { setParentsModalActivePid, toggleParentsModal },
action: { openModal },
} = useGlobalContext();

const {
action: { setParentsModalActivePid },
} = useEditorContext();

const clickAction = () => {
setParentsModalActivePid(pid);
toggleParentsModal();
openModal("parents");
};
return <button onClick={clickAction}>Edit Parents</button>;
};
Expand Down
16 changes: 8 additions & 8 deletions client/components/edit/EditorSnackbar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ import userEvent from "@testing-library/user-event";
import renderer from "react-test-renderer";
import EditorSnackbar from "./EditorSnackbar";

const mockUseEditorContext = jest.fn();
jest.mock("../../context/EditorContext", () => ({
useEditorContext: () => {
return mockUseEditorContext();
const mockUseGlobalContext = jest.fn();
jest.mock("../../context/GlobalContext", () => ({
useGlobalContext: () => {
return mockUseGlobalContext();
},
}));
jest.mock("./children/ChildList", () => () => "ChildList");

describe("EditorSnackbar", () => {
let editorValues;
let globalValues;
beforeEach(() => {
editorValues = {
globalValues = {
state: {
snackbarState: {
message: "test1",
Expand All @@ -28,7 +28,7 @@ describe("EditorSnackbar", () => {
setSnackbarState: jest.fn(),
},
};
mockUseEditorContext.mockReturnValue(editorValues);
mockUseGlobalContext.mockReturnValue(globalValues);
});

it("renders", () => {
Expand All @@ -47,7 +47,7 @@ describe("EditorSnackbar", () => {

await userEvent.setup().click(screen.getByRole("button"));

expect(editorValues.action.setSnackbarState).toHaveBeenCalledWith({
expect(globalValues.action.setSnackbarState).toHaveBeenCalledWith({
open: false,
message: "",
severity: "info",
Expand Down
4 changes: 2 additions & 2 deletions client/components/edit/EditorSnackbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import Alert from "@mui/material/Alert";
import IconButton from "@mui/material/IconButton";
import Snackbar from "@mui/material/Snackbar";
import CloseIcon from "@mui/icons-material/Close";
import { useEditorContext } from "../../context/EditorContext";
import { useGlobalContext } from "../../context/GlobalContext";

const EditorSnackbar = (): React.ReactElement => {
const {
state: {
snackbarState: { message, open, severity },
},
action: { setSnackbarState },
} = useEditorContext();
} = useGlobalContext();

const handleClose = () => {
setSnackbarState({
Expand Down
14 changes: 9 additions & 5 deletions client/components/edit/ObjectStatus.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import renderer from "react-test-renderer";
import { ObjectStatusProps, ObjectStatus } from "./ObjectStatus";
import { EditorContextProvider, ObjectDetails } from "../../context/EditorContext";
import { FetchContextProvider } from "../../context/FetchContext";
import { GlobalContextProvider } from "../../context/GlobalContext";

function getMountedObjectStatusComponent(props: ObjectStatusProps) {
return renderer.create(
<FetchContextProvider>
<EditorContextProvider>
<ObjectStatus {...props} />
</EditorContextProvider>
</FetchContextProvider>,
<GlobalContextProvider>
<FetchContextProvider>
<EditorContextProvider>
<ObjectStatus {...props} />
</EditorContextProvider>
</FetchContextProvider>
,
</GlobalContextProvider>,
);
}

Expand Down
8 changes: 6 additions & 2 deletions client/components/edit/ObjectStatus.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import styles from "./ObjectStatus.module.css";
import React from "react";
import { useGlobalContext } from "../../context/GlobalContext";
import { useEditorContext } from "../../context/EditorContext";
import ObjectLoader from "./ObjectLoader";

Expand All @@ -8,17 +9,20 @@ export interface ObjectStatusProps {
}

export const ObjectStatus = ({ pid }: ObjectStatusProps): React.ReactElement => {
const {
action: { openModal },
} = useGlobalContext();
const {
state: { objectDetailsStorage },
action: { setStateModalActivePid, toggleStateModal },
action: { setStateModalActivePid },
} = useEditorContext();
const loaded = Object.prototype.hasOwnProperty.call(objectDetailsStorage, pid);
const details = loaded ? objectDetailsStorage[pid] : {};

const stateTxt = details.state ?? "Unknown";
const clickAction = () => {
setStateModalActivePid(pid);
toggleStateModal();
openModal("state");
};
const stateMsg = loaded ? (
<button onClick={clickAction} className={styles[stateTxt.toLowerCase()]}>
Expand Down
58 changes: 43 additions & 15 deletions client/components/edit/StateModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import userEvent from "@testing-library/user-event";
import renderer from "react-test-renderer";
import StateModal from "./StateModal";

const mockUseGlobalContext = jest.fn();
jest.mock("../../context/GlobalContext", () => ({
useGlobalContext: () => {
return mockUseGlobalContext();
},
}));

const mockUseEditorContext = jest.fn();
jest.mock("../../context/EditorContext", () => ({
useEditorContext: () => {
Expand Down Expand Up @@ -41,38 +48,51 @@ jest.mock("@mui/material/Grid", () => (props) => props.children);
jest.mock("@mui/icons-material/Close", () => () => "CloseIcon");

describe("StateModal", () => {
let globalValues;
let editorValues;
let fetchContextValues;
const pid = "foo:123";
beforeEach(() => {
globalValues = {
action: {
closeModal: jest.fn(),
isModalOpen: jest.fn(),
openModal: jest.fn(),
setSnackbarState: jest.fn(),
},
};
editorValues = {
state: {
stateModalActivePid: pid,
isStateModalOpen: true,
objectDetailsStorage: {},
},
action: {
removeFromObjectDetailsStorage: jest.fn(),
setSnackbarState: jest.fn(),
toggleStateModal: jest.fn(),
},
};
mockUseEditorContext.mockReturnValue(editorValues);
fetchContextValues = {
action: {
fetchJSON: jest.fn(),
fetchText: jest.fn(),
},
};
mockUseGlobalContext.mockReturnValue(globalValues);
mockUseEditorContext.mockReturnValue(editorValues);
mockUseFetchContext.mockReturnValue(fetchContextValues);
globalValues.action.isModalOpen.mockReturnValue(true);
});

afterEach(() => {
jest.resetAllMocks();
});

it("renders correctly when closed", () => {
editorValues.state.isStateModalOpen = false;
globalValues.action.isModalOpen.mockReturnValue(false);
let tree;
renderer.act(() => {
tree = renderer.create(<StateModal />);
});
expect(globalValues.action.isModalOpen).toHaveBeenCalledWith("state");
expect(tree.toJSON()).toMatchSnapshot();
});

Expand All @@ -81,6 +101,7 @@ describe("StateModal", () => {
renderer.act(() => {
tree = renderer.create(<StateModal />);
});
expect(globalValues.action.isModalOpen).toHaveBeenCalledWith("state");
expect(tree.toJSON()).toMatchSnapshot();
});

Expand All @@ -92,6 +113,7 @@ describe("StateModal", () => {
tree = renderer.create(<StateModal />);
});
await waitFor(() => expect(fetchContextValues.action.fetchJSON).toHaveBeenCalled());
expect(globalValues.action.isModalOpen).toHaveBeenCalledWith("state");
expect(tree.toJSON()).toMatchSnapshot();
});

Expand All @@ -103,6 +125,7 @@ describe("StateModal", () => {
tree = renderer.create(<StateModal />);
});
await waitFor(() => expect(fetchContextValues.action.fetchJSON).toHaveBeenCalled());
expect(globalValues.action.isModalOpen).toHaveBeenCalledWith("state");
expect(tree.toJSON()).toMatchSnapshot();
});

Expand All @@ -114,6 +137,7 @@ describe("StateModal", () => {
render(<StateModal />);
});
await waitFor(() => expect(fetchContextValues.action.fetchJSON).toHaveBeenCalled());
expect(globalValues.action.isModalOpen).toHaveBeenCalledWith("state");
const user = userEvent.setup();
await user.click(screen.getByText("Active"));
await user.click(screen.getByText("Save"));
Expand All @@ -123,13 +147,13 @@ describe("StateModal", () => {
{ body: "Active", method: "PUT" },
),
);
expect(editorValues.action.setSnackbarState).toHaveBeenCalledWith({
expect(globalValues.action.setSnackbarState).toHaveBeenCalledWith({
message: "Status saved successfully.",
open: true,
severity: "success",
});
expect(editorValues.action.removeFromObjectDetailsStorage).toHaveBeenCalledWith(pid);
expect(editorValues.action.toggleStateModal).toHaveBeenCalled();
expect(globalValues.action.closeModal).toHaveBeenCalledWith("state");
});

it("does not save when nothing changes", async () => {
Expand All @@ -140,17 +164,18 @@ describe("StateModal", () => {
render(<StateModal />);
});
await waitFor(() => expect(fetchContextValues.action.fetchJSON).toHaveBeenCalled());
expect(globalValues.action.isModalOpen).toHaveBeenCalledWith("state");
await userEvent.setup().click(screen.getByText("Save"));
await waitFor(() =>
expect(editorValues.action.setSnackbarState).toHaveBeenCalledWith({
expect(globalValues.action.setSnackbarState).toHaveBeenCalledWith({
message: "No changes were made.",
open: true,
severity: "info",
}),
);
expect(fetchContextValues.action.fetchText).not.toHaveBeenCalled();
expect(editorValues.action.removeFromObjectDetailsStorage).not.toHaveBeenCalled();
expect(editorValues.action.toggleStateModal).not.toHaveBeenCalled();
expect(globalValues.action.openModal).not.toHaveBeenCalled();
});

it("handles save failure gracefully", async () => {
Expand All @@ -161,6 +186,7 @@ describe("StateModal", () => {
render(<StateModal />);
});
await waitFor(() => expect(fetchContextValues.action.fetchJSON).toHaveBeenCalled());
expect(globalValues.action.isModalOpen).toHaveBeenCalledWith("state");
const user = userEvent.setup();
await user.click(screen.getByText("Active"));
await user.click(screen.getByText("Save"));
Expand All @@ -170,13 +196,13 @@ describe("StateModal", () => {
{ body: "Active", method: "PUT" },
),
);
expect(editorValues.action.setSnackbarState).toHaveBeenCalledWith({
expect(globalValues.action.setSnackbarState).toHaveBeenCalledWith({
message: 'Status failed to save; "not ok"',
open: true,
severity: "error",
});
expect(editorValues.action.removeFromObjectDetailsStorage).not.toHaveBeenCalled();
expect(editorValues.action.toggleStateModal).toHaveBeenCalled();
expect(globalValues.action.closeModal).toHaveBeenCalledWith("state");
});

it("handles child save failure gracefully", async () => {
Expand All @@ -187,6 +213,7 @@ describe("StateModal", () => {
render(<StateModal />);
});
await waitFor(() => expect(fetchContextValues.action.fetchJSON).toHaveBeenCalled());
expect(globalValues.action.isModalOpen).toHaveBeenCalledWith("state");
const user = userEvent.setup();
await user.click(screen.getByText("Active"));
await user.click(screen.getByText("Update 1 children to match"));
Expand All @@ -197,13 +224,13 @@ describe("StateModal", () => {
{ body: "Active", method: "PUT" },
),
);
expect(editorValues.action.setSnackbarState).toHaveBeenCalledWith({
expect(globalValues.action.setSnackbarState).toHaveBeenCalledWith({
message: 'Status failed to save; "not ok"',
open: true,
severity: "error",
});
expect(editorValues.action.removeFromObjectDetailsStorage).not.toHaveBeenCalled();
expect(editorValues.action.toggleStateModal).toHaveBeenCalled();
expect(globalValues.action.closeModal).toHaveBeenCalledWith("state");
});

it("updates children correctly", async () => {
Expand All @@ -214,6 +241,7 @@ describe("StateModal", () => {
render(<StateModal />);
});
await waitFor(() => expect(fetchContextValues.action.fetchJSON).toHaveBeenCalled());
expect(globalValues.action.isModalOpen).toHaveBeenCalledWith("state");
const user = userEvent.setup();
await user.click(screen.getByText("Active"));
await user.click(screen.getByText("Update 1 children to match"));
Expand All @@ -224,7 +252,7 @@ describe("StateModal", () => {
{ body: "Active", method: "PUT" },
),
);
expect(editorValues.action.setSnackbarState).toHaveBeenCalledWith({
expect(globalValues.action.setSnackbarState).toHaveBeenCalledWith({
message: "Status saved successfully.",
open: true,
severity: "success",
Expand All @@ -237,6 +265,6 @@ describe("StateModal", () => {
expect(fetchContextValues.action.fetchText).toHaveBeenCalledTimes(2);
expect(editorValues.action.removeFromObjectDetailsStorage).toHaveBeenNthCalledWith(1, "foo:125");
expect(editorValues.action.removeFromObjectDetailsStorage).toHaveBeenNthCalledWith(2, pid);
expect(editorValues.action.toggleStateModal).toHaveBeenCalled();
expect(globalValues.action.closeModal).toHaveBeenCalledWith("state");
});
});
Loading