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

O3-1385: Write unit tests to test the components #7

Merged
merged 5 commits into from Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/node.js.yml
Expand Up @@ -2,9 +2,9 @@ name: Node.js CI

on:
push:
branches: [master]
branches: [main]
pull_request:
branches: [master]
branches: [main]
release:
types:
- created
Expand Down
6 changes: 3 additions & 3 deletions package.json
Expand Up @@ -14,7 +14,7 @@
"lint": "eslint src --ext js,jsx,ts,tsx",
"prettier": "prettier --write \"src/**/*.{ts,tsx}\"",
"typescript": "tsc",
"test": "jest --config jest.config.json",
"test": "jest --config jest.config.json --verbose",
"verify": "concurrently 'yarn:lint' 'yarn:test' 'yarn:typescript'",
"coverage": "yarn test -- --coverage",
"prepare": "husky install"
Expand Down Expand Up @@ -69,9 +69,9 @@
"@testing-library/dom": "^7.31.2",
"@testing-library/jest-dom": "^5.13.0",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^13.1.9",
"@types/carbon__icons-react": "^10.31.0",
"@testing-library/user-event": "^14.2.1",
"@types/carbon-components-react": "^7.34.0",
"@types/carbon__icons-react": "^10.31.0",
"@types/jest": "^26.0.23",
"@types/react": "^16.13.1",
"@types/react-dom": "^16.9.14",
Expand Down
24 changes: 1 addition & 23 deletions src/cohort-builder.test.tsx
@@ -1,32 +1,10 @@
/**
* This is the root test for this page. It simply checks that the page
* renders. If the components of your page are highly interdependent,
* (e.g., if the `Hello` component had state that communicated
* information between `Greeter` and `PatientGetter`) then you might
* want to do most of your testing here. If those components are
* instead quite independent (as is the case in this example), then
* it would make more sense to test those components independently.
*
* The key thing to remember, always, is: write tests that behave like
* users. They should *look* for elements by their visual
* characteristics, *interact* with them, and (mostly) *assert* based
* on things that would be visually apparent to a user.
*
* To learn more about how we do testing, see the following resources:
* https://kentcdodds.com/blog/how-to-know-what-to-test
* https://kentcdodds.com/blog/testing-implementation-details
* https://kentcdodds.com/blog/common-mistakes-with-react-testing-library
*
* Kent C. Dodds is the inventor of `@testing-library`:
* https://testing-library.com/docs/guiding-principles
*/
import React from "react";

import { render, cleanup } from "@testing-library/react";

import CohortBuilder from "./cohort-builder";

describe(`<CohortBuilder />`, () => {
describe("Test the cohort builder", () => {
afterEach(cleanup);
it(`renders without dying`, () => {
render(<CohortBuilder />);
Expand Down
8 changes: 4 additions & 4 deletions src/cohort-builder.tsx
Expand Up @@ -7,10 +7,10 @@ import { useTranslation } from "react-i18next";
import { search } from "./cohort-builder.resource";
import styles from "./cohort-builder.scss";
import { addToHistory } from "./cohort-builder.utils";
import { CohortResultsTable } from "./components/cohort-results-table/cohort-results-table.component";
import SearchButtonSet from "./components/search-button-set/search-button-set";
import { SearchByConcepts } from "./components/search-by-concepts/search-by-concepts.component";
import { SearchHistory } from "./components/search-history/search-history.component";
import { SearchResultsTable } from "./components/search-results-table/search-results-table.component";
import { Patient, SearchParams } from "./types/types";

interface TabItem {
Expand Down Expand Up @@ -121,11 +121,11 @@ const CohortBuilder: React.FC = () => {
))}
</Tabs>
<SearchButtonSet
handleReset={handleReset}
handleSubmit={handleSubmit}
onHandleReset={handleReset}
onHandleSubmit={handleSubmit}
isLoading={isLoading}
/>
<CohortResultsTable patients={patients} />
<SearchResultsTable patients={patients} />
<SearchHistory
isHistoryUpdated={isHistoryUpdated}
setIsHistoryUpdated={setIsHistoryUpdated}
Expand Down
23 changes: 23 additions & 0 deletions src/components/search-button-set/search-button-set.test.tsx
@@ -0,0 +1,23 @@
import React from "react";

import { render, fireEvent } from "@testing-library/react";

import SearchButtonSet from "./search-button-set";

describe("Test the search button set component", () => {
it("should be able search and reset", () => {
const handleSubmit = jest.fn();
const handleReset = jest.fn();
const { getByTestId } = render(
<SearchButtonSet
onHandleReset={handleReset}
onHandleSubmit={handleSubmit}
isLoading={false}
/>
);
fireEvent.click(getByTestId("reset-btn"));
expect(handleReset).toBeCalled();
fireEvent.click(getByTestId("search-btn"));
expect(handleSubmit).toBeCalled();
});
});
20 changes: 14 additions & 6 deletions src/components/search-button-set/search-button-set.tsx
Expand Up @@ -12,24 +12,32 @@ import styles from "./search-button-set.css";

interface SearchButtonSet {
isLoading: boolean;
handleSubmit: () => void;
handleReset: () => void;
onHandleSubmit: () => void;
onHandleReset: () => void;
}

const SearchButtonSet: React.FC<SearchButtonSet> = ({
isLoading,
handleSubmit,
handleReset,
onHandleSubmit,
onHandleReset,
}) => {
const { t } = useTranslation();

return (
<Column sm={2} md={{ offset: 4 }} className={styles.container}>
<ButtonSet className={styles.buttonSet}>
<Button kind="secondary" onClick={handleReset}>
<Button
kind="secondary"
onClick={onHandleReset}
data-testid="reset-btn"
>
{t("reset", "Reset")}
</Button>
<Button kind="primary" onClick={handleSubmit}>
<Button
kind="primary"
onClick={onHandleSubmit}
data-testid="search-btn"
>
{isLoading ? (
<InlineLoading description={t("loading", "Loading")} />
) : (
Expand Down
79 changes: 49 additions & 30 deletions src/components/search-by-concepts/search-by-concepts.component.tsx
@@ -1,4 +1,10 @@
import React, { Dispatch, SetStateAction, useEffect, useState } from "react";
import React, {
Dispatch,
SetStateAction,
useCallback,
useEffect,
useState,
} from "react";

import {
DatePicker,
Expand All @@ -15,8 +21,8 @@ import {
queryDescriptionBuilder,
} from "../../cohort-builder.utils";
import { Concept, SearchParams } from "../../types/types";
import { SearchConcept } from "../search-concept/search-concept.component";
import styles from "./search-by-concepts.style.scss";
import { SearchConcept } from "./search-concept/search-concept.component";

const operators = [
{
Expand Down Expand Up @@ -141,37 +147,12 @@ export const SearchByConcepts: React.FC<SearchByConceptsProps> = ({
},
];

useEffect(() => {
if (concept) {
handleInputValues();
}
}, [
concept,
lastDays,
lastMonths,
onOrAfter,
onOrBefore,
operator,
operatorValue,
timeModifier,
]);

useEffect(() => {
if (resetInputs) {
handleResetInputs();
}
}, [resetInputs]);

const handleLastDaysAndMonths = () => {
if (lastDays > 0 || lastMonths > 0) {
const onOrAfter = dayjs()
.subtract(lastDays, "days")
.subtract(lastMonths, "months")
.format();
setOnOrBefore(onOrAfter);
}
};

const handleDates = (dates: Date[]) => {
setOnOrAfter(dayjs(dates[0]).format());
setOnOrBefore(dayjs(dates[1]).format());
Expand All @@ -188,8 +169,14 @@ export const SearchByConcepts: React.FC<SearchByConceptsProps> = ({
setTimeModifier("ANY");
};

const handleInputValues = () => {
handleLastDaysAndMonths();
const handleInputValues = useCallback(() => {
if (lastDays > 0 || lastMonths > 0) {
const onOrAfter = dayjs()
.subtract(lastDays, "days")
.subtract(lastMonths, "months")
.format();
setOnOrBefore(onOrAfter);
}
const observations: Observation = {
modifier: "",
onOrAfter: onOrAfter,
Expand Down Expand Up @@ -219,7 +206,36 @@ export const SearchByConcepts: React.FC<SearchByConceptsProps> = ({
});
setSearchParams(composeJson(params));
setQueryDescription(queryDescriptionBuilder(observations, concept.name));
};
}, [
concept?.hl7Abbrev,
concept?.name,
concept?.uuid,
lastDays,
lastMonths,
onOrAfter,
onOrBefore,
operator,
operatorValue,
setQueryDescription,
setSearchParams,
timeModifier,
]);

useEffect(() => {
if (concept) {
handleInputValues();
}
}, [
concept,
handleInputValues,
lastDays,
lastMonths,
onOrAfter,
onOrBefore,
operator,
operatorValue,
timeModifier,
]);

return (
<div className={styles.container}>
Expand Down Expand Up @@ -286,6 +302,7 @@ export const SearchByConcepts: React.FC<SearchByConceptsProps> = ({
<Column className={styles.column} sm={2} md={{ span: 4 }}>
<Dropdown
id="timeModifier"
data-testid="timeModifier"
onChange={(data) => setTimeModifier(data.selectedItem.value)}
initialSelectedItem={observationOptions[0]}
items={observationOptions}
Expand All @@ -301,6 +318,7 @@ export const SearchByConcepts: React.FC<SearchByConceptsProps> = ({
</p>
<NumberInput
id="last-months"
data-testid="last-months"
invalidText={t("numberIsNotValid", "Number is not valid")}
min={0}
size="sm"
Expand All @@ -312,6 +330,7 @@ export const SearchByConcepts: React.FC<SearchByConceptsProps> = ({
<div className={styles.multipleInputs}>
<NumberInput
id="last-days"
data-testid="last-days"
invalidText={t("numberIsNotValid", "Number is not valid")}
min={0}
size="sm"
Expand Down