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

Unit test for browsing page #2851

Open
wants to merge 3 commits into
base: main
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
12 changes: 11 additions & 1 deletion dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,16 @@
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"test": "react-scripts test --coverage",
"eject": "react-scripts eject"
},
"jest":{
"transform": {
"^.+\\.[t|j]sx?$": "babel-jest"
webbnh marked this conversation as resolved.
Show resolved Hide resolved
},
"transformIgnorePatterns":["node_modules/(?!@patternfly)/"]
}
,
"eslintConfig": {
"extends": [
"react-app",
Expand All @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion dashboard/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've got some superfluous blank characters, here.

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`.
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change doesn't seem like it should be in a unit testing commit/PR.

}, []);

return (
Expand Down
8 changes: 0 additions & 8 deletions dashboard/src/App.test.js

This file was deleted.

26 changes: 26 additions & 0 deletions dashboard/src/modules/components/AlertComponent/Alert.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Provider } from "react-redux";
import store from "store/store";
import App from "../../../App";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this context, do we have a "root" configured, so that we don't have to use relative import paths? (I.e., can we just import this from "App" or from ./Appbecause the root issrc`?) Ditto for the other modules.

const { render, screen, fireEvent } = require("@testing-library/react");
const AppWrapper = () => {
return (
<Provider store={store}>
<App />
</Provider>
);
};
test("Alert message is displayed on initial load", () => {
render(<AppWrapper />);
const alert = screen.getByText('Want to see your own data?');
expect(alert).toBeInTheDocument();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any other attributes that we should be checking?

});

test("Alert message is closed on clicking close button", () => {
render(<AppWrapper />);
const alert = screen.getByText('Want to see your own data?');
const closeButton = screen.getByRole("button", {
name: /close info alert/i,
});
fireEvent.click(closeButton);
expect(alert).not.toBeVisible();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Provider } from "react-redux";
import store from "store/store";
import { MOCK_DATA } from "utils/mockData";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is specifically a mock for /api/v1/datasets/list with specific metadata requested. I think it would be better to give this a more specific name than just "MOCK_DATA", especially with the suggestion that a file named "mockData.js" might provide mocks for other APIs as well?

import App from "../../../App";
const { render, screen, fireEvent } = require("@testing-library/react");
const AppWrapper = () => {
return (
<Provider store={store}>
<App />
</Provider>
);
};
Comment on lines +6 to +12
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be refactored into a common module and reused in all the tests?

jest.mock("utils/api", () => {
return {
get: () => ({
data: MOCK_DATA,
status:200
}),
};
});
test("data is filtered based on date range selected from date picker", async () => {
render(<AppWrapper />);
await screen.findByText("pbench_user_benchmark1");
const datePickerInput = screen.getAllByPlaceholderText('YYYY-MM-DD');
fireEvent.change(datePickerInput[0], { target: { value: "2022-02-16" } });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we be checking that the UI has updated from YYYY-MM-DD to 2022-02-16?

Also, can the code here look at the values in the React-store? I think those would be good things to check, as well.

fireEvent.change(datePickerInput[1], { target: { value: "2022-02-20" } });
const updateBtn = screen.getByRole("button", { name: 'Update'});
fireEvent.click(updateBtn);
const datasetNameOne = screen.queryByText("pbench_user_benchmark1");
const datasetNameTwo = screen.queryByText("pbench_user_benchmark2");
const datasetNameThree = screen.queryByText("pbench_user_benchmark3");
const datasetNameFour = screen.queryByText("pbench_user_benchmark4");
const datasetNameFive = screen.queryByText("pbench_user_benchmark5");
expect(datasetNameOne).toBeInTheDocument();
expect(datasetNameTwo).toBeInTheDocument();
expect(datasetNameThree).toBeInTheDocument();
expect(datasetNameFour).not.toBeInTheDocument();
expect(datasetNameFive).not.toBeInTheDocument();
Comment on lines +29 to +38
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks to me like these assertions will fit on one line, so there's no need to use local variables for them (in-lining the expressions will cut the number of new lines of code in half...).

  expect(screen.queryByText("pbench_user_benchmark1")).toBeInTheDocument();
...
  expect(screen.queryByText("pbench_user_benchmark5")).not.toBeInTheDocument();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A similar comment applies to dashboard/src/modules/components/TableComponent/Table.test.js, and perhaps elsewhere.

});
78 changes: 78 additions & 0 deletions dashboard/src/modules/components/TableComponent/Table.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
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");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Teach me something: why do we use require() here instead of import?

const AppWrapper = () => {
return (
<Provider store={store}>
<App />
</Provider>
);
};
jest.mock("utils/api", () => {
return {
get: () => ({
data: MOCK_DATA,
status: 200,
}),
};
});
test("Page heading is displayed on initial load", async () => {
render(<AppWrapper />);
await screen.findByText("pbench_user_benchmark1");
const heading = screen.getByRole("heading", { name: 'Results' });
expect(heading).toBeInTheDocument();
});
test("data from API is displayed on initial load", async () => {
render(<AppWrapper />);
await screen.findByText("pbench_user_benchmark1");
const datasetNameOne = screen.queryByText("pbench_user_benchmark1");
const datasetNameTwo = screen.queryByText("pbench_user_benchmark2");
const datasetNameThree = screen.queryByText("pbench_user_benchmark3");
const datasetNameFour = screen.queryByText("pbench_user_benchmark4");
const datasetNameFive = screen.queryByText("pbench_user_benchmark5");
expect(datasetNameOne).toBeInTheDocument();
expect(datasetNameTwo).toBeInTheDocument();
expect(datasetNameThree).toBeInTheDocument();
expect(datasetNameFour).toBeInTheDocument();
expect(datasetNameFive).toBeInTheDocument();
});

test("row is favorited after clicking on favorite icon", async () => {
render(<AppWrapper />);
await screen.findByText("pbench_user_benchmark1");
const starBtn = screen.getAllByRole("button", {
name: 'Not starred',
});
fireEvent.click(starBtn[0]);
fireEvent.click(starBtn[1]);
const favoriteBtn = screen.getByRole("button", {
name: 'see favorites button',
});
fireEvent.click(favoriteBtn);
const datasetNameOne = screen.queryByText("pbench_user_benchmark1");
const datasetNameTwo = screen.queryByText("pbench_user_benchmark2");
const datasetNameThree = screen.queryByText("pbench_user_benchmark3");
const datasetNameFour = screen.queryByText("pbench_user_benchmark4");
const datasetNameFive = screen.queryByText("pbench_user_benchmark5");
expect(datasetNameOne).toBeInTheDocument();
expect(datasetNameTwo).toBeInTheDocument();
expect(datasetNameThree).not.toBeInTheDocument();
expect(datasetNameFour).not.toBeInTheDocument();
expect(datasetNameFive).not.toBeInTheDocument();
});
test("data is filtered based on value in search box", async () => {
render(<AppWrapper />);
await screen.findByText("pbench_user_benchmark1");
const searchBox = screen.getByPlaceholderText('Search Dataset');
fireEvent.change(searchBox, { target: { value: "pbench_user_benchmark2" } });
webbnh marked this conversation as resolved.
Show resolved Hide resolved
const searchBtn = screen.getByRole("button", {
name: 'searchButton',
});
fireEvent.click(searchBtn);
const datasetNameTwo = screen.queryByText("pbench_user_benchmark2");
const datasetNameThree = screen.queryByText("pbench_user_benchmark3");
expect(datasetNameTwo).toBeInTheDocument();
expect(datasetNameThree).not.toBeInTheDocument();
});
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ export const SearchBox = ({
<InputGroup className="searchInputGroup">
<TextInput
type="text"
placeholder="Search"
placeholder="Search Dataset"
onChange={(e) => setSearchKey(e)}
></TextInput>
<Button variant="control" onClick={search}>
<Button variant="control" onClick={search} aria-label="searchButton">
<SearchIcon />
</Button>
</InputGroup>
Expand Down
17 changes: 8 additions & 9 deletions dashboard/src/modules/components/TableComponent/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ import DatePickerWidget from "../DatePickerComponent";
import PathBreadCrumb from "../BreadCrumbComponent";
import { LoginHint, Heading, EmptyTable, SearchBox } from "./common-components";
import { getTodayMidnightUTCDate } from "utils/dateFunctions";
import { bumpToDate } from "utils/dateFunctions";

let startDate = new Date(Date.UTC(1990, 10, 4));
let endDate = getTodayMidnightUTCDate();
let endDate = bumpToDate(getTodayMidnightUTCDate(),1);
let datasetName = "";
let dataArray = [];

const TableWithFavorite = () => {
const columnNames = {
Expand All @@ -51,7 +51,7 @@ const TableWithFavorite = () => {
dispatch(getFavoritedDatasets());
}, [dispatch]);

const { publicData, favoriteRepoNames } = useSelector(
const { publicData, favoriteRepoNames,tableData } = useSelector(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you need to run Prettier again. 🙃

It would be good to develop a habit of running Prettier before each commit.

(state) => state.datasetlist
);
const setPublicData = (data) => {
Expand Down Expand Up @@ -141,20 +141,17 @@ const TableWithFavorite = () => {

<PageSection variant={PageSectionVariants.light}>
<PathBreadCrumb pathList={datasetBreadcrumb} />
<Heading
containerClass="publicDataPageTitle"
headingTitle="Results"
/>
<Heading containerClass="publicDataPageTitle" headingTitle="Results" />
<div className="filterContainer">
<SearchBox
dataArray={dataArray}
dataArray={tableData}
setPublicData={setPublicData}
startDate={startDate}
endDate={endDate}
setDatasetName={setDatasetName}
/>
<DatePickerWidget
dataArray={dataArray}
dataArray={tableData}
setPublicData={setPublicData}
datasetName={datasetName}
setDateRange={setDateRange}
Expand All @@ -167,13 +164,15 @@ const TableWithFavorite = () => {
isSelected={isSelected === "datasetListButton"}
onChange={handleButtonClick}
className="datasetListButton"
aria-label="see dataset button"
/>
<ToggleGroupItem
text={`Favorites(${favoriteRepoNames?.length})`}
buttonId="favoriteListButton"
isSelected={isSelected === "favoriteListButton"}
onChange={handleButtonClick}
className="favoriteListButton"
aria-label="see favorites button"
/>
</ToggleGroup>
<TableComposable aria-label="Favoritable table" variant="compact">
Expand Down
32 changes: 32 additions & 0 deletions dashboard/src/utils/mockData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export const MOCK_DATA = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still a bit concerned about the generic name MOCK_DATA ... this mocks the response of /datasets/list, but we'll certainly want to have other mocks in the future to test additional parts of the dashboard.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The /datasets/list response format has changed. There's now a "results" field in the JSON as well as a "next_url" for paging. Also, the dashboard now relies on the resource_id.

{
  "next_url": "",
  "results": [
    {
      "metadata": {
        "dataset.created": "2022-07-27T15:39:06+00:00"
      },
      "name": "pbench-user-benchmark_xyz.22_2022.07.27T15.39.06",
      "resource_id": "c54ab5929dc6230937402b682751c1ac"
    },
    {
      "metadata": {
        "dataset.created": "2022-07-27T15:01:57+00:00"
      },
      "name": "Short timer",
      "resource_id": "8c19617fc80580eaf6bb6808a1f8c46f"
    },
    {
      "metadata": {
        "dataset.created": "2022-07-27T13:45:02+00:00"
      },
      "name": "Soon FOUR",
      "resource_id": "4e28f76ccc9572f7e6a27898678db39d"
    },
    {
      "metadata": {
        "dataset.created": "2022-07-27T13:45:11+00:00"
      },
      "name": "Soonish",
      "resource_id": "892e506d3302ebaa466b9bc4c02f1780"
    },
    {
      "metadata": {
        "dataset.created": "2022-07-20T16:28:32+00:00"
      },
      "name": "Soon ONE",
      "resource_id": "6a4b55f64f8dd5f997be0da70a5e0d2c"
    },
    {
      "metadata": {
        "dataset.created": "2022-07-27T13:44:53+00:00"
      },
      "name": "Soon THREE",
      "resource_id": "e368132b16f8a45407c77c0a54a427fb"
    }
  ],
  "total": 6
}

{
name: "pbench_user_benchmark1",
metadata: {
"dataset.created": "2022-02-16T13:21:29+00:00",
},
},
{
name: "pbench_user_benchmark2",
metadata: {
"dataset.created": "2022-02-18T13:21:29+00:00",
},
},
{
name: "pbench_user_benchmark3",
metadata: {
"dataset.created": "2022-02-20T13:21:29+00:00",
},
},
{
name: "pbench_user_benchmark4",
metadata: {
"dataset.created": "2022-02-25T13:21:29+00:00",
},
},
{
name: "pbench_user_benchmark5",
metadata: {
"dataset.created": "2022-03-08T13:21:29+00:00",
},
},
];