diff --git a/dashboard/package.json b/dashboard/package.json
index a373f6882f..2b4a931bc7 100644
--- a/dashboard/package.json
+++ b/dashboard/package.json
@@ -40,6 +40,13 @@
"test": "react-scripts test",
"eject": "react-scripts eject"
},
+ "jest":{
+ "transform": {
+ "^.+\\.[t|j]sx?$": "babel-jest"
+ },
+ "transformIgnorePatterns":["node_modules/(?!@patternfly)/"]
+ }
+ ,
"eslintConfig": {
"extends": [
"react-app",
@@ -59,7 +66,10 @@
]
},
"devDependencies": {
+ "@babel/preset-env": "^7.17.10",
+ "babel-jest": "^28.1.0",
"css-loader": "^6.7.1",
+ "jest": "^28.1.0",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"style-loader": "^3.3.1"
diff --git a/dashboard/public/index.html b/dashboard/public/index.html
index 896deda7e5..a386a682bc 100644
--- a/dashboard/public/index.html
+++ b/dashboard/public/index.html
@@ -30,7 +30,7 @@
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
-
+
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
diff --git a/dashboard/src/App.js b/dashboard/src/App.js
index 5301b7cce5..c9e3f58991 100644
--- a/dashboard/src/App.js
+++ b/dashboard/src/App.js
@@ -10,7 +10,7 @@ import MainLayout from 'modules/containers/MainLayout';
function App() {
useEffect(() => {
const faviconLogo = document.getElementById("favicon");
- faviconLogo.setAttribute("href", favicon);
+ faviconLogo?.setAttribute("href", favicon);
}, []);
return (
diff --git a/dashboard/src/App.test.js b/dashboard/src/App.test.js
deleted file mode 100644
index 1f03afeece..0000000000
--- a/dashboard/src/App.test.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { render, screen } from '@testing-library/react';
-import App from './App';
-
-test('renders learn react link', () => {
- render();
- const linkElement = screen.getByText(/learn react/i);
- expect(linkElement).toBeInTheDocument();
-});
diff --git a/dashboard/src/modules/components/AlertComponent/Alert.test.js b/dashboard/src/modules/components/AlertComponent/Alert.test.js
new file mode 100644
index 0000000000..e70e15ed3b
--- /dev/null
+++ b/dashboard/src/modules/components/AlertComponent/Alert.test.js
@@ -0,0 +1,26 @@
+import { Provider } from "react-redux";
+import store from "store/store";
+import App from "../../../App";
+const { render, screen, fireEvent } = require("@testing-library/react");
+const AppWrapper = () => {
+ return (
+
+
+
+ );
+};
+test("Alert message is displayed on initial load", () => {
+ render();
+ const alert = screen.getByText(/want to see your own data/i);
+ expect(alert).toBeInTheDocument();
+});
+
+test("Alert message is closed on clicking close button", () => {
+ render();
+ const alert = screen.getByText(/want to see your own data/i);
+ const closeButton = screen.getByRole("button", {
+ name: /close info alert/i,
+ });
+ fireEvent.click(closeButton);
+ expect(alert).not.toBeVisible();
+});
diff --git a/dashboard/src/modules/components/DatePickerComponent/DatePicker.test.js b/dashboard/src/modules/components/DatePickerComponent/DatePicker.test.js
new file mode 100644
index 0000000000..e7711ccfd6
--- /dev/null
+++ b/dashboard/src/modules/components/DatePickerComponent/DatePicker.test.js
@@ -0,0 +1,30 @@
+import { Provider } from "react-redux";
+import store from "store/store";
+import { MOCK_DATA } from "utils/mockData";
+import App from "../../../App";
+const { render, screen, fireEvent } = require("@testing-library/react");
+const AppWrapper = () => {
+ return (
+
+
+
+ );
+};
+jest.mock("utils/api", () => {
+ return {
+ get: () => ({
+ data: MOCK_DATA,
+ }),
+ };
+});
+test("data is filtered based on date range selected from date picker", async () => {
+ render();
+ await screen.findByText("dhcp1");
+ const datePickerInput = screen.getAllByPlaceholderText(/yyyy-mm-dd/i);
+ fireEvent.change(datePickerInput[0], { target: { value: "2022-02-16" } });
+ fireEvent.change(datePickerInput[1], { target: { value: "2022-02-20" } });
+ const updateBtn = screen.getByRole("button", { name: /update/i });
+ fireEvent.click(updateBtn);
+ const cells = screen.getAllByRole("cell");
+ expect(cells).toHaveLength(12);
+});
diff --git a/dashboard/src/modules/components/HeadingComponent/Heading.test.js b/dashboard/src/modules/components/HeadingComponent/Heading.test.js
new file mode 100644
index 0000000000..d890b7f119
--- /dev/null
+++ b/dashboard/src/modules/components/HeadingComponent/Heading.test.js
@@ -0,0 +1,16 @@
+import { Provider } from "react-redux";
+import store from "store/store";
+import App from "../../../App";
+const { render, screen } = require("@testing-library/react");
+const AppWrapper = () => {
+ return (
+
+
+
+ );
+};
+test("Page heading is displayed on initial load", () => {
+ render();
+ const heading = screen.getByRole("heading", { name: /controllers/i });
+ expect(heading).toBeInTheDocument();
+});
diff --git a/dashboard/src/modules/components/SearchComponent/Search.test.js b/dashboard/src/modules/components/SearchComponent/Search.test.js
new file mode 100644
index 0000000000..bb587fe755
--- /dev/null
+++ b/dashboard/src/modules/components/SearchComponent/Search.test.js
@@ -0,0 +1,33 @@
+import { Provider } from "react-redux";
+import store from "store/store";
+import { MOCK_DATA } from "utils/mockData";
+import App from "../../../App";
+const { render, screen, fireEvent } = require("@testing-library/react");
+const AppWrapper = () => {
+ return (
+
+
+
+ );
+};
+jest.mock("utils/api", () => {
+ return {
+ get: () => ({
+ data: MOCK_DATA,
+ }),
+ };
+});
+test("data is filtered based on value in search box", async () => {
+ render();
+ await screen.findByText("dhcp1");
+ const searchBox = screen.getByPlaceholderText(/search controllers/i);
+ fireEvent.change(searchBox, { target: { value: "dhcp2" } });
+ const searchBtn = screen.getByRole("button", {
+ name: /searchButton/i,
+ });
+ fireEvent.click(searchBtn);
+ const controllerTwo = screen.queryByText("dhcp2");
+ const controllerThree = screen.queryByText("dhcp3");
+ expect(controllerTwo).toBeInTheDocument();
+ expect(controllerThree).not.toBeInTheDocument();
+});
diff --git a/dashboard/src/modules/components/SearchComponent/index.jsx b/dashboard/src/modules/components/SearchComponent/index.jsx
new file mode 100644
index 0000000000..ef8da69d36
--- /dev/null
+++ b/dashboard/src/modules/components/SearchComponent/index.jsx
@@ -0,0 +1,32 @@
+import React,{useState} from "react";
+import "./index.css"
+import { InputGroup, TextInput, Button } from "@patternfly/react-core";
+import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon";
+import { filterData } from "utils/filterDataset";
+function SearchBox({
+ dataArray,
+ setPublicData,
+ startDate,
+ endDate,
+ setControllerName,
+}) {
+ const [controllerValue, setControllerValue] = useState("");
+ const searchController = () => {
+ setPublicData(filterData(dataArray, startDate, endDate, controllerValue));
+ setControllerName(controllerValue);
+ };
+ return (
+
+ setControllerValue(e)}
+ >
+
+
+ );
+}
+
+export default SearchBox;
diff --git a/dashboard/src/modules/components/TableComponent/Table.test.js b/dashboard/src/modules/components/TableComponent/Table.test.js
new file mode 100644
index 0000000000..b83254ee44
--- /dev/null
+++ b/dashboard/src/modules/components/TableComponent/Table.test.js
@@ -0,0 +1,48 @@
+import { Provider } from "react-redux";
+import store from "store/store";
+import { MOCK_DATA } from "utils/mockData";
+import App from "../../../App";
+const {
+ render,
+ screen,
+ waitFor,
+ fireEvent,
+} = require("@testing-library/react");
+const AppWrapper = () => {
+ return (
+
+
+
+ );
+};
+jest.mock("utils/api", () => {
+ return {
+ get: () => ({
+ data: MOCK_DATA,
+ }),
+ };
+});
+
+test("data from API is displayed on initial load", async () => {
+ render();
+ const benchmarkName = await screen.findByText("pbench_user_benchmark1");
+ const cells = await screen.findAllByRole("cell");
+ await waitFor(() => expect(benchmarkName).toBeInTheDocument());
+ await waitFor(() => expect(cells).toHaveLength(20));
+});
+
+test("row is favorited after clicking on favorite icon", async () => {
+ render();
+ await screen.findByText("dhcp1");
+ const starBtn = screen.getAllByRole("button", {
+ name: /not starred/i,
+ });
+ fireEvent.click(starBtn[0]);
+ fireEvent.click(starBtn[1]);
+ const favoriteBtn = screen.getByRole("button", {
+ name: /see favorites button/i,
+ });
+ fireEvent.click(favoriteBtn);
+ const favoriteCell = screen.getAllByRole("cell");
+ expect(favoriteCell).toHaveLength(8);
+});
diff --git a/dashboard/src/utils/mockData.js b/dashboard/src/utils/mockData.js
new file mode 100644
index 0000000000..42a055f3b1
--- /dev/null
+++ b/dashboard/src/utils/mockData.js
@@ -0,0 +1,37 @@
+export const MOCK_DATA = [
+ {
+ controller: "dhcp1",
+ name: "pbench_user_benchmark1",
+ metadata: {
+ "dataset.created": "2022-02-16T13:21:29+00:00",
+ },
+ },
+ {
+ controller: "dhcp2",
+ name: "pbench_user_benchmark2",
+ metadata: {
+ "dataset.created": "2022-02-18T13:21:29+00:00",
+ },
+ },
+ {
+ controller: "dhcp3",
+ name: "pbench_user_benchmark3",
+ metadata: {
+ "dataset.created": "2022-02-20T13:21:29+00:00",
+ },
+ },
+ {
+ controller: "dhcp4",
+ name: "pbench_user_benchmark4",
+ metadata: {
+ "dataset.created": "2022-02-25T13:21:29+00:00",
+ },
+ },
+ {
+ controller: "dhcp5",
+ name: "pbench_user_benchmark5",
+ metadata: {
+ "dataset.created": "2022-03-08T13:21:29+00:00",
+ },
+ },
+];