Skip to content

Commit

Permalink
[Issue #1471]: Tests for search components (#1617)
Browse files Browse the repository at this point in the history
## Summary
Fixes #1471

## Changes 
- Tests for most of the search components
  • Loading branch information
rylew1 committed Apr 8, 2024
1 parent 4c17f9b commit 5a36cc0
Show file tree
Hide file tree
Showing 14 changed files with 777 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,24 @@ export default function SectionLinkLabel({
childrenVisible: boolean;
option: FilterOption;
}) {
// When the arrow is down, the section is collapsed, and we can expand the section
// When the arrow is up, the section is expanded, and we can collapse the section
const ariaLabel = childrenVisible ? "Collapse section" : "Expand section";

return (
<span className="grid-col flex-fill">
{childrenVisible ? (
<Icon.ArrowDropUp size={5} className="text-middle" />
<Icon.ArrowDropUp
size={5}
className="text-middle"
aria-label={ariaLabel}
/>
) : (
<Icon.ArrowDropDown size={5} className="text-middle" />
<Icon.ArrowDropDown
size={5}
className="text-middle"
aria-label={ariaLabel}
/>
)}
{option.label}{" "}
{/* Assuming you want to display the option's label instead of its ID */}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/search/SearchPagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default function SearchPagination({
name="currentPage"
ref={paginationRef}
value={page}
data-testid="hiddenCurrentPage"
/>
)}
<Pagination
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/search/SearchSortBy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const SearchSortBy: React.FC<SearchSortByProps> = ({
id="search-sort-by-select"
onChange={handleChange}
value={sortBy}
aria-label="Sort By"
>
{SORT_OPTIONS.map((option) => (
<option key={option.value} value={option.value}>
Expand Down
49 changes: 49 additions & 0 deletions frontend/tests/components/search/SearchBar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import "@testing-library/jest-dom";

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

import React from "react";
import SearchBar from "../../../src/components/search/SearchBar";
import { axe } from "jest-axe";

// Mock the hook since it's used in the component
const mockUpdateQueryParams = jest.fn();

jest.mock("../../../src/hooks/useSearchParamUpdater", () => ({
useSearchParamUpdater: () => ({
updateQueryParams: mockUpdateQueryParams,
}),
}));

describe("SearchBar", () => {
const initialQueryParams = "initial query";

it("should not have basic accessibility issues", async () => {
const { container } = render(
<SearchBar initialQueryParams={initialQueryParams} />,
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});

it("updates the input value when typing in the search field", () => {
render(<SearchBar initialQueryParams={initialQueryParams} />);

const input = screen.getByRole("searchbox");
fireEvent.change(input, { target: { value: "new query" } });

expect(input).toHaveValue("new query");
});

it("calls updateQueryParams with the correct argument when submitting the form", () => {
render(<SearchBar initialQueryParams={initialQueryParams} />);

const input = screen.getByRole("searchbox");
fireEvent.change(input, { target: { value: "new query" } });

const searchButton = screen.getByRole("button", { name: /search/i });
fireEvent.click(searchButton);

expect(mockUpdateQueryParams).toHaveBeenCalledWith("new query", "query");
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import "@testing-library/jest-dom/extend-expect";

import SearchFilterAccordion, {
FilterOption,
} from "../../../../src/components/search/SearchFilterAccordion/SearchFilterAccordion";
import { fireEvent, render, screen } from "@testing-library/react";

import React from "react";
import { axe } from "jest-axe";

const initialFilterOptions: FilterOption[] = [
{
id: "funding-instrument-cooperative_agreement",
label: "Cooperative Agreement",
value: "cooperative_agreement",
},
{
id: "funding-instrument-grant",
label: "Grant",
value: "grant",
},
{
id: "funding-instrument-procurement_contract",
label: "Procurement Contract ",
value: "procurement_contract",
},
{
id: "funding-instrument-other",
label: "Other",
value: "other",
},
];

describe("SearchFilterAccordion", () => {
const title = "Test Accordion";
const queryParamKey = "status";
const initialQueryParams = new Set("");

it("should not have basic accessibility issues", async () => {
const { container } = render(
<SearchFilterAccordion
initialFilterOptions={initialFilterOptions}
title={title}
queryParamKey={queryParamKey}
initialQueryParams={initialQueryParams}
formRef={React.createRef()}
/>,
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});

it("displays the correct checkbox labels", () => {
render(
<SearchFilterAccordion
initialFilterOptions={initialFilterOptions}
title={title}
queryParamKey={queryParamKey}
initialQueryParams={initialQueryParams}
formRef={React.createRef()}
/>,
);

expect(screen.getByText("Cooperative Agreement")).toBeInTheDocument();
expect(screen.getByText("Grant")).toBeInTheDocument();
expect(screen.getByText("Procurement Contract")).toBeInTheDocument();
expect(screen.getByText("Other")).toBeInTheDocument();
});

it("displays select all and clear all correctly", () => {
render(
<SearchFilterAccordion
initialFilterOptions={initialFilterOptions}
title={title}
queryParamKey={queryParamKey}
initialQueryParams={initialQueryParams}
formRef={React.createRef()}
/>,
);

const selectAllButton = screen.getByText("Select All");
expect(selectAllButton).toBeInTheDocument();
expect(selectAllButton).toBeEnabled();

const clearAllButton = screen.getByText("Clear All");
expect(clearAllButton).toBeInTheDocument();
expect(clearAllButton).toBeDisabled();

const cooperativeAgreementCheckbox = screen.getByLabelText(
"Cooperative Agreement",
);

// after clicking one of the boxes, both select all and clear all should be enabled
fireEvent.click(cooperativeAgreementCheckbox);
expect(selectAllButton).toBeEnabled();
expect(clearAllButton).toBeEnabled();
});

it("has hidden attribute when collapsed", () => {
render(
<SearchFilterAccordion
initialFilterOptions={initialFilterOptions}
title={title}
queryParamKey={queryParamKey}
initialQueryParams={initialQueryParams}
formRef={React.createRef()}
/>,
);

const accordionToggleButton = screen.getByTestId(
"accordionButton_funding-instrument-filter",
);
const contentDiv = screen.getByTestId(
"accordionItem_funding-instrument-filter",
);
expect(contentDiv).toHaveAttribute("hidden");

// Toggle the accordion and the hidden attribute should be removed
fireEvent.click(accordionToggleButton);
expect(contentDiv).not.toHaveAttribute("hidden");
});

it("checks boxes correctly and updates count", () => {
render(
<SearchFilterAccordion
initialFilterOptions={initialFilterOptions}
title={title}
queryParamKey={queryParamKey}
initialQueryParams={initialQueryParams}
formRef={React.createRef()}
/>,
);

const cooperativeAgreementCheckbox = screen.getByLabelText(
"Cooperative Agreement",
);
fireEvent.click(cooperativeAgreementCheckbox);

const grantCheckbox = screen.getByLabelText("Grant");
fireEvent.click(grantCheckbox);

// Verify the count updates to 2
const countSpan = screen.getByText("2", {
selector: ".usa-tag.usa-tag--big.radius-pill.margin-left-1",
});
expect(countSpan).toBeInTheDocument();

// Verify the checkboxes are checked
expect(cooperativeAgreementCheckbox).toBeChecked();
expect(grantCheckbox).toBeChecked();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import "@testing-library/jest-dom";

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

import React from "react";
import SearchFilterCheckbox from "../../../../src/components/search/SearchFilterAccordion/SearchFilterCheckbox";
import { axe } from "jest-axe";

const mockIncrement = jest.fn();
const mockDecrement = jest.fn();
const mockUpdateCheckedOption = jest.fn();
const option = {
id: "test-option",
label: "Test Option",
value: "test",
isChecked: false,
};
describe("SearchFilterCheckbox", () => {
it("should not have basic accessibility issues", async () => {
const { container } = render(
<SearchFilterCheckbox
option={option}
increment={mockIncrement}
decrement={mockDecrement}
mounted={true}
updateCheckedOption={mockUpdateCheckedOption}
accordionTitle={"Test Accordion"}
/>,
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});

it("calls the appropriate handlers when the checkbox is clicked", async () => {
render(
<SearchFilterCheckbox
option={option}
increment={mockIncrement}
decrement={mockDecrement}
mounted={true}
updateCheckedOption={mockUpdateCheckedOption}
accordionTitle={"Test Accordion"}
/>,
);

// Simulate user clicking the checkbox
const checkbox = screen.getByLabelText(option.label);
fireEvent.click(checkbox);

// Wait for the increment function to be called
await waitFor(() => {
expect(mockIncrement).toHaveBeenCalledTimes(1);
});

// Wait for the updateCheckedOption function to be called with the checkbox being checked
await waitFor(() => {
expect(mockUpdateCheckedOption).toHaveBeenCalledWith(option.id, true);
});

// Simulate user clicking the checkbox again to uncheck it
fireEvent.click(checkbox);

// TODO (Issue #1618): Resolve issues with unchecking

// await waitFor(() => {
// expect(mockDecrement).toHaveBeenCalledTimes(1);
// });

// // Wait for the updateCheckedOption function to be called with the checkbox being unchecked
// await waitFor(() => {
// expect(mockUpdateCheckedOption).toHaveBeenCalledWith(option.id, false);
// });
});
});
Loading

0 comments on commit 5a36cc0

Please sign in to comment.