Skip to content

Commit

Permalink
replace manage facility admin screen dropdowns with combos (#6439)
Browse files Browse the repository at this point in the history
* refactor using truss

* add tests

* temporarily wrap things in act

* fix accessibility violations and refactor tests

* scope down unnecessary changes

* use recommended userEvent setup pattern

* fix mocks

* move gql alias to before each hook

* switch selector

* rework e2e to work with combo box

* add org util query to simplify selectors

* add extracted combo box component

* add forwardRef hook

* relax label selectors
  • Loading branch information
fzhao99 authored Sep 7, 2023
1 parent 7620c47 commit 8b99a27
Show file tree
Hide file tree
Showing 7 changed files with 319 additions and 181 deletions.
38 changes: 24 additions & 14 deletions cypress/e2e/11-support-manage-facility.cy.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
import {loginHooks, testNumber} from "../support/e2e";
import {addMockFacility, whoAmI} from "../utils/testing-data-utils";
import {graphqlURL} from "../utils/request-utils";
import {aliasGraphqlOperations} from "../utils/graphql-test-utils";
import { loginHooks, testNumber } from "../support/e2e";
import { addMockFacility, whoAmI, getOrganizationById } from "../utils/testing-data-utils";
import { graphqlURL } from "../utils/request-utils";
import { aliasGraphqlOperations } from "../utils/graphql-test-utils";

loginHooks();
describe("Support admin: manage facility", () => {
let organizationId="";
let organizationId = "";
let organizationName = "";
let facilityId = "";
let facilityCreated = {
id:"",
name:`RainbowCenter-${testNumber()}`,
}
id: "",
name: `RainbowCenter-${testNumber()}`
};

before(() => {
addMockFacility(facilityCreated.name).then(response=>{
addMockFacility(facilityCreated.name).then(response => {
facilityCreated.id = response.body.data.addFacility.id;
});

whoAmI().then((res) => {
organizationId = res.body.data.whoami.organization.id;
facilityId = res.body.data.whoami.organization.facilities[0].id;

getOrganizationById(organizationId).then((res) => {
organizationName = res.body.data.organization.name;
});
});

});

beforeEach(() => {
cy.intercept("POST", graphqlURL, (req) => {
aliasGraphqlOperations(req)
aliasGraphqlOperations(req);
});
});

Expand All @@ -38,11 +46,13 @@ describe("Support admin: manage facility", () => {

// selects organization
cy.wait("@GetAllOrganizations");
cy.get("div.bg-base-lightest select").first().select(organizationId);

// selects facility
// selects org combo box
cy.get("input[role=\"combobox\"]").first().type(`${organizationName}{enter}`);

// selects facility combo box
cy.wait("@GetFacilitiesByOrgId");
cy.get("div.bg-base-lightest select").eq(1).select(facilityCreated.id);
cy.get("input[role=\"combobox\"]").last().type(`${facilityCreated.name}{enter}`);

// clicks search button
cy.get("button").contains("Search").click();
Expand All @@ -62,7 +72,7 @@ describe("Support admin: manage facility", () => {
cy.contains(`Delete ${facilityCreated.name}`).should("not.exist");
});

it("Deletes a facility",()=>{
it("Deletes a facility", () => {
cy.get("button").contains("Delete facility").click();
cy.get("button").contains("Yes, delete facility").click();
cy.get(".Toastify").contains(`Facility ${facilityCreated.name} successfully deleted`);
Expand Down
63 changes: 39 additions & 24 deletions cypress/utils/testing-data-utils.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,47 @@
export const whoAmI=()=>{
export const whoAmI = () => {
return cy.makePOSTRequest({
operationName: "WhoAmI",
variables: {},
query:
"query WhoAmI {\n whoami {\n organization {\n id\n facilities {\n id\n }\n }\n} \n}",
"query WhoAmI {\n whoami {\n organization {\n id\n facilities {\n id\n }\n }\n} \n}"
});
}
};

export const getOrganizationById = (organizationId) => {
return cy.makePOSTRequest({
operationName: "Organization",
variables: { id: organizationId },
query:
`query Organization($id: ID!) {
organization(id: $id){
id
name
}
}`
});
};


export const addMockFacility=(facilityName)=>{
return cy.makePOSTRequest({
operationName: "AddFacility",
variables: {
"testingFacilityName":facilityName,
"street":"123 maint street",
"state":"NJ","zipCode":"07601",
"orderingProviderFirstName":"Jane",
"orderingProviderLastName":"Austen",
"orderingProviderNPI":"1234567890",
"orderingProviderStreet":"",
"orderingProviderStreetTwo":"",
"orderingProviderCity":"",
"orderingProviderState":"",
"orderingProviderZipCode":"",
"orderingProviderPhone":"7328392412",
"devices":[]},
query:
`mutation AddFacility(
export const addMockFacility = (facilityName) => {
return cy.makePOSTRequest({
operationName: "AddFacility",
variables: {
"testingFacilityName": facilityName,
"street": "123 maint street",
"state": "NJ", "zipCode": "07601",
"orderingProviderFirstName": "Jane",
"orderingProviderLastName": "Austen",
"orderingProviderNPI": "1234567890",
"orderingProviderStreet": "",
"orderingProviderStreetTwo": "",
"orderingProviderCity": "",
"orderingProviderState": "",
"orderingProviderZipCode": "",
"orderingProviderPhone": "7328392412",
"devices": []
},
query:
`mutation AddFacility(
$testingFacilityName: String!
$street: String!
$state: String!
Expand Down Expand Up @@ -70,6 +85,6 @@ return cy.makePOSTRequest({
) {
id
}
}`,
});
}`
});
};
35 changes: 35 additions & 0 deletions frontend/src/app/commonComponents/ComboBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ComboBox as TrussComboBox, Label } from "@trussworks/react-uswds";
import React, { ComponentPropsWithRef, forwardRef } from "react";

import Required from "./Required";

type TrussComponentProps = ComponentPropsWithRef<typeof TrussComboBox>;
export type ComboBoxProps = TrussComponentProps & {
required?: boolean;
};

// props here are only the required ones from Truss and can be extended
// as needed with additional values.
const ComboBox: React.FC<ComboBoxProps> = forwardRef(function (
{ id, name, required, options, onChange, disabled }: ComboBoxProps,
ref
) {
return (
<>
<Label htmlFor={id}>
{name} {required && <Required />}
</Label>
<TrussComboBox
name={name}
id={id}
options={options}
onChange={onChange}
disabled={disabled}
ref={ref}
inputProps={{ "aria-required": required }}
/>
</>
);
});

export default ComboBox;
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { act, render, screen, waitFor, within } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import React from "react";
import { ComboBoxRef } from "@trussworks/react-uswds";
import userEvent from "@testing-library/user-event";

import { Option } from "../../commonComponents/Dropdown";

import FacilitySelectFilter from "./FacilitySelectFilter";
import { initialState, ManageFacilityState } from "./ManageFacility";

export const getOrgComboBoxElements = () => {
const orgSelectionDiv = screen.getByTestId("org-selection-container");
const orgComboBoxInput = screen.getByLabelText(/organization/i);
const orgComboBoxList = within(orgSelectionDiv).getByTestId(
"combo-box-option-list"
);
return [orgComboBoxInput, orgComboBoxList] as const;
};

export const getFacilityComboBoxElements = () => {
const facilitySelectionDiv = screen.getByTestId(
"facility-selection-container"
);
const facilityComboBoxInput = screen.getByLabelText(/testing facility/i);
const facilityComboBoxList = within(facilitySelectionDiv).getByTestId(
"combo-box-option-list"
);
return [facilityComboBoxInput, facilityComboBoxList] as const;
};
describe("FacilitySelectFilter", () => {
const handleClearFilter = jest.fn();
const handleSelectOrg = jest.fn();
Expand All @@ -22,7 +44,9 @@ describe("FacilitySelectFilter", () => {
orgOptions: Option[],
facilityOptions: Option[],
manageFacilityState: ManageFacilityState
) =>
) => {
const orgRef = React.createRef<ComboBoxRef>();
const facilityRef = React.createRef<ComboBoxRef>();
render(
<MemoryRouter>
<FacilitySelectFilter
Expand All @@ -34,50 +58,56 @@ describe("FacilitySelectFilter", () => {
onSearch={handleSearch}
manageFacilityState={manageFacilityState}
loading={true}
orgRef={orgRef}
facilityRef={facilityRef}
/>
</MemoryRouter>
);
};
const user = userEvent.setup();

it("disables controls when loading data", () => {
renderWithMocks([], [], initialState);

expect(
screen.getByRole("combobox", { name: /organization/i })
).toBeDisabled();
expect(screen.getByRole("combobox", { name: /facility/i })).toBeDisabled();
const [orgDropdown] = getOrgComboBoxElements();
const [facilityDropdown] = getFacilityComboBoxElements();

expect(facilityDropdown).toBeDisabled();
expect(orgDropdown).toBeDisabled();
});

it("calls handleClearFilter upon clicking clear filters button", async () => {
renderWithMocks(mockOrganizationOptions, mockFacilityOptions, {
orgId: "123",
facilityId: "",
facilityId: undefined,
facility: undefined,
});
const clearFiltersBtn = screen.getByRole("button", {
name: /clear facility selection filters/i,
});
expect(clearFiltersBtn).toBeEnabled();
fireEvent.click(clearFiltersBtn);
await act(() => user.click(clearFiltersBtn));
await waitFor(() => expect(handleClearFilter).toHaveBeenCalled());
});

it("calls event handlers when organization is selected", async () => {
renderWithMocks(mockOrganizationOptions, mockFacilityOptions, initialState);
const orgDropdown = screen.getByRole("combobox", { name: /organization/i });
fireEvent.change(orgDropdown, { target: { value: "123" } });

const [, orgDropdown] = getOrgComboBoxElements();

await act(() => user.selectOptions(orgDropdown, ["organization-123"]));
await waitFor(() => expect(handleSelectOrg).toHaveBeenCalled());
});

it("calls event handlers when facility is selected", async () => {
renderWithMocks(mockOrganizationOptions, mockFacilityOptions, {
orgId: "123",
facilityId: "",
facilityId: undefined,
facility: undefined,
});
const facilityDropdown = screen.getByRole("combobox", {
name: /facility/i,
});
fireEvent.change(facilityDropdown, { target: { value: "123" } });

const [, facilityDropdown] = getFacilityComboBoxElements();
await act(() => user.selectOptions(facilityDropdown, ["facility-123"]));
await waitFor(() => expect(handleSelectFacility).toHaveBeenCalled());
});

Expand All @@ -87,15 +117,12 @@ describe("FacilitySelectFilter", () => {
facilityId: "123",
facility: undefined,
});
const facilityDropdown = screen.getByRole("combobox", {
name: /facility/i,
});
fireEvent.change(facilityDropdown, { target: { value: "123" } });

const searchBtn = screen.getByRole("button", {
name: /search/i,
});
fireEvent.click(searchBtn);
expect(searchBtn).toBeEnabled();
await act(() => user.click(searchBtn));

await waitFor(() => expect(handleSearch).toHaveBeenCalled());
});
Expand Down
Loading

0 comments on commit 8b99a27

Please sign in to comment.