Skip to content

Commit

Permalink
Make add patient cypress e2e spec 2 rerunnable
Browse files Browse the repository at this point in the history
  • Loading branch information
emyl3 committed Oct 20, 2023
1 parent 3056514 commit 8f79f91
Show file tree
Hide file tree
Showing 35 changed files with 441 additions and 142 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,24 @@ public List<ApiOrganization> organizations(@Argument Boolean identityVerified) {
.collect(Collectors.toList());
}

/**
* Retrieves a list of all organizations, filtered by name
*
* @return a list of organizations
*/
@QueryMapping
@AuthorizationConfiguration.RequireGlobalAdminUser
public List<ApiOrganization> organizationsByName(@Argument String name) {
List<Organization> orgs = _organizationService.getOrganizationsByName(name);
if (orgs.isEmpty()) {
return null;
} else {
return orgs.stream()
.map(o -> new ApiOrganization(o, _organizationService.getFacilities(o)))
.collect(Collectors.toList());
}
}

/**
* Retrieves a list of all pending organizations AND organization queue items
*
Expand Down
1 change: 1 addition & 0 deletions backend/src/main/resources/graphql/admin.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# which is enforced in the API not in the schema validator.
extend type Query {
organizations(identityVerified: Boolean): [Organization!]!
organizationsByName(name: String!): [Organization]
pendingOrganizations: [PendingOrganization!]!
organization(id: ID!): Organization
facilityStats(facilityId: ID!): FacilityStats
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package gov.cdc.usds.simplereport.api.organization;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import gov.cdc.usds.simplereport.api.model.ApiOrganization;
import gov.cdc.usds.simplereport.api.model.ApiPendingOrganization;
import gov.cdc.usds.simplereport.api.model.accountrequest.OrganizationAccountRequest;
import gov.cdc.usds.simplereport.api.model.errors.IllegalGraphqlArgumentException;
Expand Down Expand Up @@ -75,4 +77,29 @@ void organization_null() {
verify(organizationService).getOrganizationById(id);
verify(organizationService, times(0)).getFacilities(org);
}

@Test
void organizationsByName_success() {
String orgName = "org name";
Organization org = new Organization(orgName, "type", "123", true);
when(organizationService.getOrganizationsByName(orgName)).thenReturn(List.of(org));

organizationMutationResolver.organizationsByName(orgName);

verify(organizationService).getOrganizationsByName(orgName);
verify(organizationService).getFacilities(org);
}

@Test
void organizationsByName_null() {
String orgName = "org name";
Organization org = new Organization(orgName, "type", "123", true);
when(organizationService.getOrganizationsByName(orgName)).thenReturn(List.of());

List<ApiOrganization> actual = organizationMutationResolver.organizationsByName(orgName);

assertThat(actual).isNull();
verify(organizationService).getOrganizationsByName(orgName);
verify(organizationService, never()).getFacilities(org);
}
}
5 changes: 4 additions & 1 deletion cypress/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"plugins": ["cypress"],
"extends": ["plugin:cypress/recommended"]
"extends": ["plugin:cypress/recommended"],
"rules": {
"cypress/require-data-selectors": "warn"
}
}
7 changes: 7 additions & 0 deletions cypress/cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ module.exports = {
getMultiplexDeviceName() {
return global.multiplexDeviceName;
},
setSpecName(name) {
global.specName = name;
return name;
},
getSpecName() {
return global.specName || null;
},
});
on("before:browser:launch", (browser = {}, launchOptions = {}) => {
launchOptions.args = launchOptions.args.filter(
Expand Down
113 changes: 56 additions & 57 deletions cypress/e2e/02-add_patient.cy.js
Original file line number Diff line number Diff line change
@@ -1,67 +1,66 @@
import { generatePatient, loginHooks } from "../support/e2e";

const patient = generatePatient();

import { generatePatient, loginHooks, testNumber } from "../support/e2e";
import { cleanUpPreviousOrg, setupOrgAndFacility } from "../utils/setup-utils";
let patient= generatePatient();
describe("Adding a single patient", () => {
loginHooks();
before("store patient info", () => {
cy.task("setPatientName", patient.fullName);
cy.task("setPatientDOB", patient.dobForPatientLink);
cy.task("setPatientPhone", patient.phone);
cy.task("getSpecName")
.then((specName) => {
if (specName) {
cleanUpPreviousOrg(specName);
}
specName = `${testNumber()}-cypress-spec-2`
cy.task("setSpecName", specName)
setupOrgAndFacility(specName);
})
});
it("navigates to the add patient form", () => {
cy.visit("/");
cy.get(".usa-nav-container");
cy.get("#desktop-patient-nav-link").click();
cy.get(".prime-container");
cy.get("#add-patient").click();
cy.get("#individual_add-patient").click();
cy.get(".prime-edit-patient").contains("Add new patient");
it("navigates to and fills out add patient form", () => {
cy.visit('/');
cy.get('[data-cy="desktop-patient-nav-link"]').click();
cy.get('[data-cy="add-patients-button"]').click();
cy.get('[data-cy="individual"]').click();
cy.get('[data-cy="add-patient-header"]').contains("Add new patient");
cy.injectSRAxe();
cy.checkAccessibility(); // Patient form
});
it("fills out some of the form fields", () => {
cy.get('input[name="firstName"]').type(patient.firstName);
cy.get('input[name="birthDate"]').type(patient.dobForInput);
cy.get('input[name="number"]').type(patient.phone);
cy.get('input[value="MOBILE"]+label').click();
cy.get('input[name="gender"][value="female"]+label').click();
cy.get('input[name="genderIdentity"][value="female"]+label').click();
cy.get('input[name="street"]').type(patient.address);
cy.get('select[name="state"]').select(patient.state);
cy.get('input[name="zipCode"]').type(patient.zip);
cy.get('select[name="role"]').select("STUDENT");
cy.get(".prime-edit-patient").contains("Student ID");
cy.get('input[name="lookupId"]').type(patient.studentId);
cy.get('input[name="race"][value="other"]+label').click();
cy.get('input[name="ethnicity"][value="refused"]+label').click();
cy.get('input[name="residentCongregateSetting"][value="NO"]+label').click();
cy.get('input[name="employedInHealthcare"][value="NO"]+label').click();
});
it("shows what fields are missing on submit", () => {
cy.get(".prime-save-patient-changes").first().click();

cy.get(".prime-edit-patient").contains("Last name is missing");
cy.get(".prime-edit-patient").contains("Testing facility is missing");
cy.get(".prime-edit-patient").contains("City is missing");
});
it("fills out the remaining fields, submits and checks for the patient", () => {
cy.get('input[name="lastName"]').type(patient.lastName);
cy.get('input[name="city"]').type(patient.city);
cy.get('select[name="facilityId"]').select("All facilities");
cy.get(".prime-save-patient-changes").first().click();
cy.get(
'.modal__container input[name="addressSelect-person"][value="userAddress"]+label',
).click();

cy.checkAccessibility();

cy.get(".modal__container #save-confirmed-address").click();
cy.get(".usa-card__header").contains("Patients");
cy.get(".usa-card__header").contains("Showing");
cy.get("#search-field-small").type(patient.lastName);
cy.get(".prime-container").contains(patient.fullName);

cy.checkAccessibility();
cy.checkAccessibility(); // empty patient form
// fill out form
cy.get('[data-cy="personForm-firstName-input"]').type(patient.firstName);
cy.get('[data-cy="personForm-dob-input"]').type(patient.dobForInput);
cy.get('[data-cy="phone-input-0"]').type(patient.phone);
cy.get('[data-cy="radio-group-option-phoneType-0-MOBILE"]').click();
cy.get('[data-cy="radio-group-option-genderIdentity-female"]').click();
cy.get('[data-cy="radio-group-option-gender-female"]').click();
cy.get('[data-cy="street-input"]').type(patient.address);
cy.get('[data-cy="state-input"]').select(patient.state);
cy.get('[data-cy="zip-input"]').type(patient.zip);
cy.get('[data-cy="personForm-role-input"]').select("STUDENT");
cy.get('[data-cy="add-patient-page"]').contains("Student ID");
cy.get('[data-cy="personForm-lookupId-input"]').type(patient.studentId);
cy.get('[data-cy="radio-group-option-race-other"]').click();
cy.get('[data-cy="radio-group-option-ethnicity-refused"]').click();
cy.get('[data-cy="radio-group-option-residentCongregateSetting-NO"]').click();
cy.get('[data-cy="radio-group-option-employedInHealthcare-NO"]').click();
cy.get('[data-cy="add-patient-save-button"]').eq(0).click();
// check for errors
cy.get('[data-cy="add-patient-page"]').contains("Last name is missing");
cy.get('[data-cy="add-patient-page"]').contains("Testing facility is missing");
cy.get('[data-cy="add-patient-page"]').contains("City is missing");
cy.checkAccessibility(); // patient form with errors
// fill out remaining form
cy.get('[data-cy="personForm-lastName-input"]').type(patient.lastName);
cy.get('[data-cy="city-input"]').type(patient.city);
cy.get('[data-cy="personForm-facility-input"]').select("All facilities");
cy.get('[data-cy="add-patient-save-button"]').eq(0).click();
cy.get('[data-cy="radio-group-option-addressSelect-person-userAddress"]').click();
cy.checkAccessibility(); // address validation modal
cy.get('[data-cy="save-address-confirmation-button"]').click();
// check for newly created patient on Manage Patients page
cy.get('[data-cy="manage-patients-header"]').contains("Patients");
cy.get('[data-cy="manage-patients-header"]').contains("Showing");
cy.get('[data-cy="manage-patients-search-input"]').type(patient.lastName);
cy.get('[data-cy="manage-patients-page"]').contains(patient.fullName);
cy.checkAccessibility(); // manage patients page
});
});
11 changes: 5 additions & 6 deletions cypress/e2e/10-save_and_start_covid_test.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,12 @@ describe("Save and start covid test", () => {
context("edit patient and save and start test", () => {
it("searches for the patient", () => {
cy.visit("/");
cy.get(".usa-nav-container");
cy.get("#desktop-patient-nav-link").click();
cy.get(".sr-patient-list").should("exist");
cy.get(".sr-patient-list").contains("Loading...").should("not.exist");
cy.get("#search-field-small").type(lastName);
cy.get('[data-cy="desktop-patient-nav-link"]').click();
cy.get('[data-cy="manage-patients-header"]').contains("Patients");
cy.get('[data-cy="manage-patients-header"]').contains("Showing");
cy.get('[data-cy="manage-patients-search-input"]').type(lastName);
cy.wait("@GetPatientsByFacility");
cy.get(".sr-patient-list").contains(patientName).should("exist");
cy.get('[data-cy="manage-patients-page"]').contains(patientName);
});

it("edits the found patient and clicks save and start test ", () => {
Expand Down
27 changes: 12 additions & 15 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

import "cypress-localstorage-commands";
import { authenticator } from "otplib";
import { graphqlURL } from "../utils/request-utils";
import {addOrgToQueueURL, graphqlURL} from "../utils/request-utils";

// read environment variables

Expand Down Expand Up @@ -95,20 +95,6 @@ Cypress.Commands.add("login", () => {
});
});

Cypress.Commands.add("selectFacility", () => {
cy.get("body").then(($body) => {
if (
$body
.text()
.includes(
"Please select the testing facility where you are working today.",
)
) {
cy.get(".usa-card__body").last().click();
}
});
});

Cypress.Commands.add("addDevice", (device) => {
cy.get('input[name="name"]').type(device.name);
cy.get('input[name="model"]').type(device.model);
Expand Down Expand Up @@ -178,6 +164,17 @@ Cypress.Commands.add("makePOSTRequest", (requestBody) => {
);
});

Cypress.Commands.add("makeAccountRequest", (requestBody) => {
cy.request({
method: "POST",
url: addOrgToQueueURL,
headers: {
"Content-Type": "application/json",
},
body: requestBody,
});
});

Cypress.Commands.add("injectSRAxe", () => {
return isLocalRun
? cy.injectAxe({
Expand Down
10 changes: 6 additions & 4 deletions cypress/support/e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import "cypress-axe";

const { faker } = require("@faker-js/faker");
const dayjs = require("dayjs");

Cypress.Keyboard.defaults({
keystrokeDelay: 0,
})

Check notice

Code scanning / CodeQL

Semicolon insertion Note

Avoid automated semicolon insertion (92% of all statements in
the enclosing script
have an explicit semicolon).
export const testNumber = () => {
return Math.round(Date.now() / 1000);
};
Expand All @@ -31,8 +33,8 @@ const getDobFormat = () => {
// Generate a random patient
export const generatePatient = () => {
const patient = {};
patient.firstName = faker.name.firstName();
patient.lastName = faker.name.lastName();
patient.firstName = faker.person.firstName();
patient.lastName = faker.person.lastName();
patient.fullName = `${patient.lastName}, ${patient.firstName}`;
patient.dob = dayjs(
faker.date.between({ from: "1920-01-01", to: "2002-12-31" }),
Expand All @@ -44,7 +46,7 @@ export const generatePatient = () => {
patient.city = "Definitely not Washington";
patient.state = "DC";
patient.zip = "20503";
patient.studentId = faker.datatype.uuid();
patient.studentId = faker.string.uuid();
return patient;
};

Expand Down
6 changes: 3 additions & 3 deletions cypress/utils/request-utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export const graphqlURL = `${
Cypress.env("BACKEND_URL") || "http://localhost:8080"
}/graphql`;
const backendURL = Cypress.env("BACKEND_URL") || "http://localhost:8080";
export const graphqlURL = `${backendURL}/graphql`;
export const addOrgToQueueURL = `${backendURL}/account-request/organization-add-to-queue`;
58 changes: 58 additions & 0 deletions cypress/utils/setup-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
accessOrganization,
addMockFacility,
createOrganization,
getOrganizationsByName, getPatientsByFacilityId,
markOrganizationAsDeleted, markPatientAsDeleted,
verifyPendingOrganization
} from "./testing-data-utils";
import { generateUser } from "../support/e2e";

const createOrgName = (specName) => {
return `${specName}-org`;
}

const createFacilityName = (specName) => {
return `${specName}-facility`;
}

const createAndVerifyOrganization = (orgName) => {
const adminUser = generateUser();
return createOrganization(orgName, adminUser.email)
.then((res) => verifyPendingOrganization(res.body.orgExternalId))
}
const archivePatientsForFacility = (facilityId) => {
return getPatientsByFacilityId(facilityId)
.then((res) => {
let patients = res.body.data.patients;
if (patients.length > 0) {
patients.map(
(patient) => markPatientAsDeleted(patient.internalId, true))
}
})
}

export const cleanUpPreviousOrg = (specName) => {
let orgName = createOrgName(specName);
getOrganizationsByName(orgName)
.then((res) => {
let orgs = res.body.data.organizationsByName;
let org = orgs.length > 1 ? orgs[0] : null;
if (org) {
let facilities = org.facilities
if (facilities.length > 0) {
facilities.map((facility) => archivePatientsForFacility(facility.id))
}
markOrganizationAsDeleted(org.id, true);
}
})
}

export const setupOrgAndFacility = (specName) => {
let orgName = createOrgName(specName);
let facilityName = createFacilityName(specName);
createAndVerifyOrganization(orgName)
.then(() => getOrganizationsByName(orgName))
.then((res) => accessOrganization(res.body.data.organizationsByName[0].externalId))
.then(() => addMockFacility(facilityName))
};
Loading

0 comments on commit 8f79f91

Please sign in to comment.