Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAT-7118 Action Center Setup #175

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
63 changes: 52 additions & 11 deletions src/components/cqlLibraryLanding/CqlLibraryLanding.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import "@testing-library/jest-dom";
// NOTE: jest-dom adds handy assertions to Jest and is recommended, but not required

import * as React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import NewCqlLibrary from "./CqlLibraryLanding";
import { CqlLibraryServiceApi } from "../../api/useCqlLibraryServiceApi";
import { ApiContextProvider, ServiceConfig } from "../../api/ServiceContext";
import userEvent from "@testing-library/user-event";
import { Model } from "@madie/madie-models";
import { useFeatureFlags } from "@madie/madie-util";

const abortController = new AbortController();

Expand Down Expand Up @@ -73,14 +74,14 @@ jest.mock("../../hooks/useOktaTokens", () => () => ({
getAccessToken: () => "test.jwt",
}));

const mockCqlLibraryServiceApi = {
fetchCqlLibraries: jest.fn().mockResolvedValue(cqlLibrary),
} as unknown as CqlLibraryServiceApi;

jest.mock("../../api/useCqlLibraryServiceApi", () =>
jest.fn(() => mockCqlLibraryServiceApi)
);

const mockCqlLibraryServiceApi = {
fetchCqlLibraries: jest.fn().mockResolvedValue(cqlLibrary),
} as unknown as CqlLibraryServiceApi;

// mocking useHistory
const mockPush = jest.fn();
jest.mock("react-router-dom", () => ({
Expand All @@ -101,8 +102,11 @@ describe("Cql Library Page", () => {
<NewCqlLibrary />
</ApiContextProvider>
);
const cqlLibrary1 = await screen.findByText("TestCqlLibrary1");
expect(cqlLibrary1).toBeInTheDocument();
await waitFor(() => {
const cqlLibrary1 = screen.getByText("TestCqlLibrary1");
expect(cqlLibrary1).toBeInTheDocument();
});

const cqlLibrary1Model = await screen.findByText("QI-Core v4.1.1");
expect(cqlLibrary1Model).toBeInTheDocument();
expect(mockCqlLibraryServiceApi.fetchCqlLibraries).toHaveBeenCalledWith(
Expand All @@ -127,8 +131,10 @@ describe("Cql Library Page", () => {
<NewCqlLibrary />
</ApiContextProvider>
);
const cqlLibrary1 = await screen.findByText("TestCqlLibrary1");
expect(cqlLibrary1).toBeInTheDocument();
await waitFor(() => {
const cqlLibrary1 = screen.getByText("TestCqlLibrary1");
expect(cqlLibrary1).toBeInTheDocument();
});
expect(mockCqlLibraryServiceApi.fetchCqlLibraries).toHaveBeenCalledWith(
true,
abortController.signal
Expand Down Expand Up @@ -168,8 +174,11 @@ describe("Cql Library Page", () => {
<NewCqlLibrary />
</ApiContextProvider>
);
const cqlLibrary1 = await screen.findByText("TestCqlLibrary1");
expect(cqlLibrary1).toBeInTheDocument();
await waitFor(() => {
const cqlLibrary1 = screen.getByText("TestCqlLibrary1");
expect(cqlLibrary1).toBeInTheDocument();
});

expect(mockCqlLibraryServiceApi.fetchCqlLibraries).toHaveBeenCalledWith(
true,
abortController.signal
Expand Down Expand Up @@ -207,4 +216,36 @@ describe("Cql Library Page", () => {
fireEvent.click(screen.getByTestId("library-filter-submit"));
expect(cqlLibrary2).not.toBeInTheDocument();
});

test("Checkbox tests", async () => {
(useFeatureFlags as jest.Mock).mockClear().mockImplementation(() => ({
LibraryListCheckboxes: true,
LibraryListButtons: true,
}));
render(
<ApiContextProvider value={serviceConfig}>
<NewCqlLibrary />
</ApiContextProvider>
);
await waitFor(() => {
const cqlLibrary1 = screen.getByText("TestCqlLibrary1");
expect(cqlLibrary1).toBeInTheDocument();
});

mockCqlLibraryServiceApi.fetchCqlLibraries = jest.fn().mockResolvedValue([
{
id: "67180dd54665c8239413ba90",
cqlLibraryName: "TestLib",
createdAt: "2024-10-22T20:40:53.212Z",
model: "QI-Core v4.1.1",
version: "0.0.000",
draft: false,
},
]);
const checkBoxes = await screen.findAllByRole("checkbox");
expect(checkBoxes.length).toBe(3);
userEvent.click(checkBoxes[1]);
const draftButton = await screen.findByTestId("draft-action-btn");
expect(draftButton).not.toBeDisabled();
});
});
84 changes: 47 additions & 37 deletions src/components/cqlLibraryLanding/CqlLibraryLanding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
import { Divider, TextField, IconButton } from "@mui/material";
import useCqlLibraryServiceApi from "../../api/useCqlLibraryServiceApi";
import CqlLibraryList from "../cqlLibraryList/CqlLibraryList";
import { CqlLibraryListActionCenter as ActionCenter } from "./cqlLibraryListActionCenter/CqlLibraryListActionCenter";
import * as _ from "lodash";
import { CqlLibrary } from "@madie/madie-models";
import CreateNewLibraryDialog from "../common/CreateNewLibraryDialog";
import { useDocumentTitle } from "@madie/madie-util";
import { useDocumentTitle, useFeatureFlags } from "@madie/madie-util";
import {
MadieSpinner,
Button,
Expand All @@ -18,9 +19,11 @@

function CqlLibraryLanding() {
useDocumentTitle("MADiE Libraries");
const featureFlags = useFeatureFlags();
const [activeTab, setActiveTab] = useState(0);
const [cqlLibraryList, setCqlLibraryList] = useState(null);
const [loading, setLoading] = useState(true);
const [selectedLibraries, setSelectedLibraries] = useState<CqlLibrary[]>([]);
const cqlLibraryServiceApi = useRef(useCqlLibraryServiceApi()).current;
const [filter, setFilter] = useState("");
const [currentFilter, setCurrentFilter] = useState("");
Expand Down Expand Up @@ -49,7 +52,7 @@
if (cqlLibraryList != null && cqlLibraryList.length > 0) {
setCurrentFilter(filter);
}
}, [cqlLibraryList]);

Check warning on line 55 in src/components/cqlLibraryLanding/CqlLibraryLanding.tsx

View workflow job for this annotation

GitHub Actions / Checkout, install, lint, build and test with coverage

React Hook useEffect has a missing dependency: 'filter'. Either include it or remove the dependency array. You can also replace multiple useState variables with useReducer if 'setCurrentFilter' needs the current value of 'filter'

const handleTabChange = (event, nextTab) => {
setCqlLibraryList(null);
Expand Down Expand Up @@ -136,42 +139,48 @@
</section>
<div>
<form onSubmit={submitFilter}>
<table style={{ marginLeft: 20, marginTop: 20, marginBottom: 20 }}>
<thead>
<tr>
<td>
<TextField
sx={{
"& .MuiOutlinedInput-notchedOutline": {
borderColor: "#8C8C8C",
borderRadius: "3px",
},
}}
label="Filter Libraries"
onChange={(newFilter) => {
setFilter(newFilter.target.value);
}}
type="search"
inputProps={{
"data-testid": "library-filter-input",
"aria-required": "false",
}}
InputProps={searchInputProps}
value={filter}
/>
</td>{" "}
<td>
<Button
style={{ marginLeft: 10, marginBottom: 20 }}
type="submit"
data-testid="library-filter-submit"
>
Filter
</Button>
</td>
</tr>
</thead>
</table>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
margin: 20,
}}
>
<div style={{ display: "flex", alignItems: "center" }}>
<TextField
sx={{
"& .MuiOutlinedInput-notchedOutline": {
borderColor: "#8C8C8C",
borderRadius: "3px",
},
}}
label="Filter Libraries"
onChange={(newFilter) => {
setFilter(newFilter.target.value);
}}
type="search"
inputProps={{
"data-testid": "library-filter-input",
"aria-required": "false",
}}
InputProps={searchInputProps}
value={filter}
/>
<Button
style={{ marginLeft: 10, marginBottom: 20 }}
type="submit"
data-testid="library-filter-submit"
>
Filter
</Button>
</div>
{featureFlags?.LibraryListButtons && (
<div className="action-center-holder">
<ActionCenter libraries={selectedLibraries} />
</div>
)}
</div>
</form>
</div>
<div>
Expand All @@ -188,6 +197,7 @@
)
}
onListUpdate={loadCqlLibraries}
setSelectedLibraries={setSelectedLibraries}
/>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { useEffect } from "react";
import { Button, Grid } from "@material-ui/core";
import DeleteAction from "./deleteAction/DeleteAction";
import DraftAction from "./draftAction/DraftAction";
import VersionAction from "./versionAction/VersionAction";
import { CqlLibrary } from "@madie/madie-models";

import {
checkUserCanDelete,
checkUserCanEdit,
useFeatureFlags,
} from "@madie/madie-util";

interface PropTypes {
libraries: CqlLibrary[];
}

export function CqlLibraryListActionCenter(props: PropTypes) {
const { libraries } = props;

const canEdit = libraries
? checkUserCanEdit(
libraries[0]?.librarySet?.owner,
libraries[0]?.librarySet?.acls
)
: false;
const canDelete = libraries
? checkUserCanDelete(libraries[0]?.librarySet?.owner, libraries[0]?.draft)
: false;

useEffect(() => {}, []);
return (
<div data-testid="action-center">
<DeleteAction
libraries={libraries}
canEdit={canEdit}
canDelete={canDelete}
onClick={() => {}}
/>

<VersionAction
libraries={libraries}
canEdit={canEdit}
onClick={() => {}}
/>

<DraftAction libraries={libraries} canEdit={canEdit} onClick={() => {}} />
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import * as React from "react";
import { render, screen } from "@testing-library/react";
import DeleteAction, { DEL_LIBRARY, NOTHING_SELECTED } from "./DeleteAction";
import { CqlLibrary, Model } from "@madie/madie-models";

const mockUser = "test user";
jest.mock("@madie/madie-util", () => ({
useOktaTokens: () => ({
getUserName: () => mockUser,
}),
}));

const library = {
id: "67180dd54665c8239413ba90",
cqlLibraryName: "TestLib",
createdAt: "2024-10-22T20:40:53.212Z",
model: "QI-Core v4.1.1",
version: "0.0.000",
draft: true,
} as CqlLibrary;

describe("DeleteAction", () => {
it("Should disable action btn if no library selected", () => {
render(
<DeleteAction
libraries={[]}
canDelete={true}
onClick={() => {}}
canEdit={true}
/>
);
expect(screen.getByTestId("delete-action-btn")).toBeDisabled();
expect(screen.getByTestId("delete-action-tooltip")).toHaveAttribute(
"aria-label",
NOTHING_SELECTED
);
});

it("Should enable action btn if user select one library ", () => {
render(
<DeleteAction
canDelete={true}
libraries={[library]}
onClick={() => {}}
canEdit={true}
/>
);
expect(screen.getByTestId("delete-action-btn")).not.toBeDisabled();
expect(screen.getByTestId("delete-action-tooltip")).toHaveAttribute(
"aria-label",
DEL_LIBRARY
);
});
it("Should disable action btn if user cannot edit ", () => {
render(
<DeleteAction
canDelete={false}
libraries={[library]}
onClick={() => {}}
canEdit={false}
/>
);
expect(screen.getByTestId("delete-action-btn")).toBeDisabled();
expect(screen.getByTestId("delete-action-tooltip")).toHaveAttribute(
"aria-label",
NOTHING_SELECTED
);
});

it("Should disable btn if user selects two libraries", () => {
const library2 = library;
render(
<DeleteAction
canDelete={true}
libraries={[library, library2]}
onClick={() => {}}
canEdit={true}
/>
);
expect(screen.getByTestId("delete-action-btn")).toBeDisabled();
expect(screen.getByTestId("delete-action-tooltip")).toHaveAttribute(
"aria-label",
NOTHING_SELECTED
);
});
});
Loading
Loading