Skip to content

Commit

Permalink
Add unarchive patient functionality for support admins
Browse files Browse the repository at this point in the history
  • Loading branch information
emyl3 committed Aug 25, 2023
1 parent 61680e0 commit 68e8720
Show file tree
Hide file tree
Showing 11 changed files with 490 additions and 82 deletions.
6 changes: 6 additions & 0 deletions frontend/src/app/supportAdmin/SupportAdmin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
orgAccessPageTitle,
orgFacilityColumnTitle,
usersAndPatientsColumnTitle,
unarchivePatientTitle,
} from "./pageTitles";

type CategoryMenuProps = {
Expand Down Expand Up @@ -92,6 +93,11 @@ const SupportAdmin = () => {
{manageUserPageTitle}
</LinkWithQuery>
</li>
<li>
<LinkWithQuery to="/admin/unarchive-patient">
{unarchivePatientTitle}
</LinkWithQuery>
</li>
</CategoryMenu>
{hivEnabled && (
<CategoryMenu heading="Beta">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
GetOrganizationWithFacilitiesDocument,
GetPatientsByFacilityWithOrgDocument,
GetPatientsCountByFacilityWithOrgDocument,
UnarchivePatientDocument,
} from "../../../generated/graphql";
import * as srToast from "../../utils/srToast";

Expand Down Expand Up @@ -69,6 +70,67 @@ export const mockOrg2: UnarchivePatientOrganization = {
facilities: [],
};

const mocksWithPatients = [
{
request: {
query: GetOrganizationsDocument,
variables: {
identityVerified: true,
},
},
result: {
data: {
organizations: [mockOrg2, mockOrg1],
},
},
},
{
request: {
query: GetOrganizationWithFacilitiesDocument,
variables: {
id: mockOrg1.internalId,
},
},
result: {
data: {
organization: mockOrg1,
},
},
},
{
request: {
query: GetPatientsByFacilityWithOrgDocument,
variables: {
facilityId: mockFacility1.id,
pageNumber: 0,
pageSize: 20,
archivedStatus: ArchivedStatus.Archived,
orgExternalId: mockOrg1.externalId,
},
},
result: {
data: {
patients: [mockPatient1, mockPatient2],
},
},
},
{
request: {
query: GetPatientsCountByFacilityWithOrgDocument,
variables: {
facilityId: mockFacility1.id,
archivedStatus: ArchivedStatus.Archived,
orgExternalId: mockOrg1.externalId,
},
},
result: {
data: {
patientsCount: 2,
},
},
},
];

const axe = configureAxe({
rules: {
// disable landmark rules when testing isolated components.
Expand Down Expand Up @@ -125,7 +187,9 @@ describe("Unarchive patient", () => {
render(
<Provider store={mockedStore}>
<MockedProvider mocks={mocks} addTypename={false}>
<UnarchivePatient />
<MemoryRouter>
<UnarchivePatient />
</MemoryRouter>
</MockedProvider>
</Provider>
);
Expand Down Expand Up @@ -181,7 +245,9 @@ describe("Unarchive patient", () => {
render(
<Provider store={mockedStore}>
<MockedProvider mocks={mocks} addTypename={false}>
<UnarchivePatient />
<MemoryRouter>
<UnarchivePatient />
</MemoryRouter>
</MockedProvider>
</Provider>
);
Expand All @@ -194,67 +260,126 @@ describe("Unarchive patient", () => {
);
});
it("displays patients table on valid search", async () => {
mocks = [
render(
<Provider store={mockedStore}>
<MockedProvider mocks={mocksWithPatients} addTypename={false}>
<MemoryRouter>
<UnarchivePatient />
</MemoryRouter>
</MockedProvider>
</Provider>
);
await waitForElementToBeRemoved(() =>
screen.queryByText("Loading Organizations …")
);
await expect(screen.getByText("Clear filters")).toBeDisabled();
await searchByOrgAndFacility();
checkPatientResultRows();
expect(await axe(document.body)).toHaveNoViolations();
await act(
async () => await userEvent.click(screen.getByText("Clear filters"))
);
expect(screen.getByLabelText("Testing facility *")).toHaveDisplayValue(
"- Select -"
);
expect(screen.getByLabelText("Organization *")).toHaveDisplayValue(
"- Select -"
);
expect(
screen.getByText(
"Filter by organization and testing facility to display archived patients."
)
).toBeInTheDocument();
// show form errors
await clickSearch();
expect(screen.getByText("Organization is required")).toBeInTheDocument();
expect(
screen.getByText("Testing facility is required")
).toBeInTheDocument();
expect(await axe(document.body)).toHaveNoViolations();
});

it("displays unarchive patient modal and unarchives patient", async () => {
let alertErrorSpy: jest.SpyInstance;
let alertSuccessSpy: jest.SpyInstance;
alertErrorSpy = jest.spyOn(srToast, "showError");
alertSuccessSpy = jest.spyOn(srToast, "showSuccess");

let additionalMocks = [
{
request: {
query: GetOrganizationsDocument,
query: UnarchivePatientDocument,
variables: {
identityVerified: true,
id: mockPatient1.internalId,
orgExternalId: mockOrg1.externalId,
},
},
result: {
data: {
organizations: [mockOrg2, mockOrg1],
},
errors: [
new GraphQLError(
"A wild error appeared",
null,
null,
null,
null,
null,
{ code: "ERROR_CODE" }
),
],
},
},
{
request: {
query: GetOrganizationWithFacilitiesDocument,
query: GetPatientsByFacilityWithOrgDocument,
variables: {
id: mockOrg1.internalId,
facilityId: mockFacility1.id,
pageNumber: 0,
pageSize: 20,
archivedStatus: ArchivedStatus.Archived,
orgExternalId: mockOrg1.externalId,
},
},
result: {
data: {
organization: mockOrg1,
patients: [mockPatient1, mockPatient2],
},
},
},
{
request: {
query: GetPatientsByFacilityWithOrgDocument,
query: GetPatientsCountByFacilityWithOrgDocument,
variables: {
facilityId: mockFacility1.id,
pageNumber: 0,
pageSize: 20,
archivedStatus: ArchivedStatus.Archived,
orgExternalId: mockOrg1.externalId,
},
},
result: {
data: {
patients: [mockPatient1, mockPatient2],
patientsCount: 2,
},
},
},
{
request: {
query: GetPatientsCountByFacilityWithOrgDocument,
query: UnarchivePatientDocument,
variables: {
facilityId: mockFacility1.id,
archivedStatus: ArchivedStatus.Archived,
id: mockPatient2.internalId,
orgExternalId: mockOrg1.externalId,
},
},
result: {
data: {
patientsCount: 2,
setPatientIsDeleted: {
internalId: mockPatient2.internalId,
},
},
},
},
];

mocks = [...mocksWithPatients, ...additionalMocks];

render(
<Provider store={mockedStore}>
<MockedProvider mocks={mocks} addTypename={false}>
Expand All @@ -267,41 +392,50 @@ describe("Unarchive patient", () => {
await waitForElementToBeRemoved(() =>
screen.queryByText("Loading Organizations …")
);
await expect(screen.getByText("Clear filters")).toBeDisabled();
await selectDropdown("Organization *", mockOrg1.name);
await waitFor(async () =>
expect(screen.getByLabelText("Testing facility *")).toHaveTextContent(
"Mars Facility"
)
await searchByOrgAndFacility();
await act(async () => screen.getAllByText("Unarchive")[0].click());
expect(screen.getByRole("dialog")).toHaveTextContent(
/Are you sure you want to unarchive Gutmann, Rod\?/
);
await selectDropdown("Testing facility *", mockFacility1.name);
await clickSearch();
await waitForElementToBeRemoved(() => screen.queryAllByText("Loading..."));
checkPatientResultRows();
expect(await axe(document.body)).toHaveNoViolations();
await act(
async () => await userEvent.click(screen.getByText("Clear filters"))
);
expect(screen.getByLabelText("Testing facility *")).toHaveDisplayValue(
"- Select -"
await act(async () =>
expect(await axe(document.body)).toHaveNoViolations()
);
expect(screen.getByLabelText("Organization *")).toHaveDisplayValue(
"- Select -"
await act(async () => screen.getByText("Yes, I'm sure").click());
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
await waitFor(() => {
expect(alertErrorSpy).toHaveBeenCalledWith(
"Please escalate this issue to the SimpleReport team.",
"Error unarchiving patient"
);
});
checkPatientResultRows();
await act(async () => screen.getAllByText("Unarchive")[1].click());
expect(screen.getByRole("dialog")).toHaveTextContent(
/Are you sure you want to unarchive Mode, Mia\?/
);
expect(
screen.getByText(
"Filter by organization and testing facility to display archived patients."
)
).toBeInTheDocument();
// show form errors
await clickSearch();
expect(screen.getByText("Organization is required")).toBeInTheDocument();
expect(
screen.getByText("Testing facility is required")
).toBeInTheDocument();
await act(async () => screen.getByText("Yes, I'm sure").click());
await waitFor(() => {
expect(alertSuccessSpy).toHaveBeenCalledWith(
"",
"Patient successfully unarchived"
);
});
expect(await axe(document.body)).toHaveNoViolations();
});
});

const searchByOrgAndFacility = async () => {
await selectDropdown("Organization *", mockOrg1.name);
await waitFor(async () =>
expect(screen.getByLabelText("Testing facility *")).toHaveTextContent(
"Mars Facility"
)
);
await selectDropdown("Testing facility *", mockFacility1.name);
await clickSearch();
await waitForElementToBeRemoved(() => screen.queryAllByText("Loading..."));
};

export const clickSearch = async () => {
await act(async () => await userEvent.click(screen.getByText("Search")));
};
Expand Down
Loading

0 comments on commit 68e8720

Please sign in to comment.