From 7f0d302c6068f88ec5a99596bc5af25395bde8ae Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Mon, 29 Apr 2024 11:16:33 +0530 Subject: [PATCH 01/30] Update README to specify to use local backend for cypress tests --- README.md | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6e36f52b3f1..dbb306a1bd8 100644 --- a/README.md +++ b/README.md @@ -73,12 +73,33 @@ Authenticate to staging API with any of the following credentials #### 🧪 Run cypress tests -Ensure that the development server is running and then run the cypress tests in either of the ways described below. +To run cypress tests locally, you'll need to setup the backend to run locally and load dummy data required for cypress to the database. See [docs](https://github.com/coronasafe/care#self-hosting). + +Once backend is running locally, you'll have to ensure your local front-end is connected to local backend, by setting the `CARE_API` env. + +```env +#.env +CARE_API=http://127.0.0.1:9000 +``` + +Once done, start the development server by running + +```sh +npm run dev +``` + +Once development server is running, then run the cypress tests in either of the ways described below. + +```sh +npm run cypress:run # To run all tests in headless mode. +``` + +```sh +npm run cypress:run:gui # To run all tests in headed mode. +``` ```sh -$ npm run cypress:run # To run all tests in headless mode. -$ npm run cypress:run:gui # To run all tests in headed mode. -$ npm run cypress:open # To debug and run tests individually. +npm run cypress:open # To debug and run tests individually. ``` - Failed test screenshots are saved in `cypress/screenshots` From 283d0983a698ce4db3a1160310a468c7b9b19b86 Mon Sep 17 00:00:00 2001 From: Ashraf Mohammed <98876115+AshrafMd-1@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:19:56 +0530 Subject: [PATCH 02/30] add loader (#7720) --- src/Components/ExternalResult/ResultList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/ExternalResult/ResultList.tsx b/src/Components/ExternalResult/ResultList.tsx index 9d34b397026..0759b47d73a 100644 --- a/src/Components/ExternalResult/ResultList.tsx +++ b/src/Components/ExternalResult/ResultList.tsx @@ -194,7 +194,7 @@ export default function ResultList() { }); } - if (loading) { + if (loading || !data) { manageResults = ( From e28f92d35a54e78727a8d9defb9ca7c806e60a82 Mon Sep 17 00:00:00 2001 From: Ashesh <3626859+Ashesh3@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:21:52 +0530 Subject: [PATCH 03/30] Change home facility indicator in linked facilities slideover (#7710) * Change home facility indicator in linked facilitites slideover * Update home facility indicator styling in ManageUsers.tsx --- src/Components/Users/ManageUsers.tsx | 33 ++++++++++++++++++---------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/Components/Users/ManageUsers.tsx b/src/Components/Users/ManageUsers.tsx index b4fb9e8b10a..76940fefc79 100644 --- a/src/Components/Users/ManageUsers.tsx +++ b/src/Components/Users/ManageUsers.tsx @@ -465,7 +465,7 @@ export default function ManageUsers() { open={expandFacilityList} setOpen={setExpandFacilityList} slideFrom="right" - title={t("facilities")} + title={t("linked_facilities")} dialogClass="md:w-[400px]" > @@ -728,6 +728,7 @@ export function UserFacilities(props: { user: any }) { handleOk={handleUnlinkFacilitySubmit} /> )} +
+
+ {isLoading || userFacilitiesLoading ? (
@@ -757,13 +760,23 @@ export function UserFacilities(props: { user: any }) {
{/* Home Facility section */} {user?.home_facility_object && ( -
-
- {t("home_facility")} -
+
-
- {user?.home_facility_object?.name} +
+
+ {user?.home_facility_object?.name}{" "} + + + Home Facility + +
-
)} {/* Linked Facilities section */} {!!userFacilities?.results.length && ( -
-
- {t("linked_facilities")} -
+
{userFacilities.results.map( (facility: FacilityModel, i: number) => { From 63c90b90512a2cab4d3dc7e2e3aefe72916a4977 Mon Sep 17 00:00:00 2001 From: Ayush Chauhan <77507609+ayushchauhan12@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:22:53 +0530 Subject: [PATCH 04/30] changes made in i18n files (#7688) --- src/Components/Facility/ConsultationForm.tsx | 3 ++- src/Components/Patient/PatientInfoCard.tsx | 2 +- src/Locale/en/Common.json | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index 6a33d1d1bdf..e0c79823434 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -64,6 +64,7 @@ import ConfirmDialog from "../Common/ConfirmDialog.js"; import request from "../../Utils/request/request.js"; import routes from "../../Redux/api.js"; import useQuery from "../../Utils/request/useQuery.js"; +import { t } from "i18next"; const Loading = lazy(() => import("../Common/Loading")); const PageTitle = lazy(() => import("../Common/PageTitle")); @@ -1477,7 +1478,7 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { > - Treating Physician:{" "} + {t("treating_doctor")}:{" "} {consultation?.treating_physician_object ? `${consultation?.treating_physician_object.first_name} ${consultation?.treating_physician_object.last_name}` diff --git a/src/Locale/en/Common.json b/src/Locale/en/Common.json index 84466c99a72..e2556587e96 100644 --- a/src/Locale/en/Common.json +++ b/src/Locale/en/Common.json @@ -162,5 +162,6 @@ "DD/MM/YYYY": "DD/MM/YYYY", "clear_all_filters": "Clear All Filters", "summary": "Summary", - "report": "Report" + "report": "Report", + "treating_doctor":"Treating Doctor" } \ No newline at end of file From 1ae0f334ca02401df88d9e3dd5626d3d64b928d2 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Tue, 30 Apr 2024 11:53:02 +0530 Subject: [PATCH 05/30] Adds missing required validation for death confirmed doctor in discharge as expired popup (#7683) * Adds missing required validation for death confirmed doctor in discharge as expired popup * fix error * fix error not shown --- src/Components/Facility/DischargeModal.tsx | 25 +++++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Components/Facility/DischargeModal.tsx b/src/Components/Facility/DischargeModal.tsx index c81ab2cf74e..e2dd14dce79 100644 --- a/src/Components/Facility/DischargeModal.tsx +++ b/src/Components/Facility/DischargeModal.tsx @@ -24,6 +24,7 @@ import CircularProgress from "../Common/components/CircularProgress"; import { FacilitySelect } from "../Common/FacilitySelect"; import { FacilityModel } from "./models"; import dayjs from "../../Utils/dayjs"; +import { FieldError } from "../Form/FieldValidators"; interface PreDischargeFormInterface { new_discharge_reason: number | null; @@ -121,15 +122,22 @@ const DischargeModal = ({ if ( preDischargeForm.new_discharge_reason == - DISCHARGE_REASONS.find((i) => i.text == "Expired")?.id && - !preDischargeForm.discharge_notes.trim() + DISCHARGE_REASONS.find((i) => i.text == "Expired")?.id ) { - setErrors({ - ...errors, - discharge_notes: "Please enter the cause of death", - }); - setIsSendingDischargeApi(false); - return; + const newErrors: Record = {}; + + if (!preDischargeForm.discharge_notes.trim()) { + newErrors["discharge_notes"] = "Please enter the cause of death"; + } + if (!preDischargeForm.death_confirmed_doctor?.trim()) { + newErrors["death_confirmed_doctor"] = "Field is required"; + } + + if (Object.entries(newErrors).length) { + setErrors({ ...errors, ...newErrors }); + setIsSendingDischargeApi(false); + return; + } } const dischargeDetails = { @@ -310,6 +318,7 @@ const DischargeModal = ({ { setPreDischargeForm((form) => { From 4568e5ffcf60b28d64e7f938bfd0e60ebba1337f Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Wed, 1 May 2024 00:01:36 +0530 Subject: [PATCH 06/30] Fixes issue preventing from administering down titration prescriptions (#7743) * Fixes issues with administering down titration prescriptions * fix for create prescription form --- src/Components/Medicine/CreatePrescriptionForm.tsx | 2 +- src/Components/Medicine/EditPrescriptionForm.tsx | 2 +- .../AdministrationTableRow.tsx | 2 +- src/Components/Medicine/PrescriptionBuilder.tsx | 2 +- src/Components/Medicine/validators.ts | 14 ++++++++------ 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Components/Medicine/CreatePrescriptionForm.tsx b/src/Components/Medicine/CreatePrescriptionForm.tsx index fcc9443eaa3..b918d5781fe 100644 --- a/src/Components/Medicine/CreatePrescriptionForm.tsx +++ b/src/Components/Medicine/CreatePrescriptionForm.tsx @@ -92,7 +92,7 @@ export default function CreatePrescriptionForm(props: { optionValue={(key) => key} /> {field("dosage_type").value === "TITRATED" ? ( -
+
key} /> {field("dosage_type").value === "TITRATED" ? ( -
+
{t("edit_caution_note")}
} - className="w-full max-w-3xl lg:min-w-[600px]" + className="w-full max-w-4xl lg:min-w-[768px]" > {t("modification_caution_note")}
} - className="w-full max-w-3xl lg:min-w-[600px]" + className="w-full max-w-4xl lg:min-w-[768px]" > targetDosage) - ) - return "Dosage should be between start and target dosage"; + if (baseDosage && targetDosage) { + const [min, max] = [baseDosage, targetDosage].sort((a, b) => a - b); + + if (!(min <= valueDosage && valueDosage <= max)) { + return "Dosage should be between start and target dosage"; + } + } }; }; From 284610010cd68c42cc1cd00d0612ab3e07e5f6ce Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Mon, 6 May 2024 20:54:46 +0530 Subject: [PATCH 07/30] MEWS Score (#7761) --- .../e2e/patient_spec/patient_logupdate.cy.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/cypress/e2e/patient_spec/patient_logupdate.cy.ts b/cypress/e2e/patient_spec/patient_logupdate.cy.ts index 859cf623f30..470d8d8fab3 100644 --- a/cypress/e2e/patient_spec/patient_logupdate.cy.ts +++ b/cypress/e2e/patient_spec/patient_logupdate.cy.ts @@ -154,6 +154,38 @@ describe("Patient Log Update in Normal, Critical and TeleIcu", () => { cy.verifyContentPresence("#basic-information", [additionalSymptoms]); }); + it("Create a normal log update to verify MEWS Score Functionality", () => { + patientPage.visitPatient(domicilaryPatient); + patientConsultationPage.clickEditConsultationButton(); + patientConsultationPage.selectPatientSuggestion("Domiciliary Care"); + cy.submitButton("Update Consultation"); + cy.verifyNotification("Consultation updated successfully"); + cy.closeNotification(); + patientLogupdate.clickLogupdate(); + // Verify the MEWS Score reflection + patientLogupdate.selectPatientCategory(patientCategory); + patientLogupdate.typeSystolic(patientSystolic); + patientLogupdate.typeDiastolic(patientDiastolic); + patientLogupdate.typePulse(patientPulse); + patientLogupdate.typeTemperature(patientTemperature); + patientLogupdate.typeRespiratory(patientRespiratory); + cy.get("#consciousness_level-2").click(); + cy.submitButton("Save"); + cy.verifyNotification("Consultation Updates details created successfully"); + cy.closeNotification(); + cy.verifyContentPresence("#consultation-buttons", ["9"]); + // Verify the Incomplete data will give blank info + patientLogupdate.clickLogupdate(); + patientLogupdate.selectPatientCategory(patientCategory); + patientLogupdate.typeSystolic(patientSystolic); + patientLogupdate.typeDiastolic(patientDiastolic); + patientLogupdate.typePulse(patientPulse); + cy.submitButton("Save"); + cy.verifyNotification("Consultation Updates details created successfully"); + cy.closeNotification(); + cy.verifyContentPresence("#consultation-buttons", ["-"]); + }); + afterEach(() => { cy.saveLocalStorage(); }); From ca4040e499d3ff12b34f32afc59af2ea06f0b12d Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Mon, 6 May 2024 20:54:56 +0530 Subject: [PATCH 08/30] Duplicate medicine (#7764) --- cypress/e2e/patient_spec/patient_manage.cy.ts | 15 ------ .../patient_spec/patient_prescription.cy.ts | 49 +++++++++++++++++++ .../pageobject/Patient/PatientPrescription.ts | 10 ++-- 3 files changed, 54 insertions(+), 20 deletions(-) create mode 100644 cypress/e2e/patient_spec/patient_prescription.cy.ts diff --git a/cypress/e2e/patient_spec/patient_manage.cy.ts b/cypress/e2e/patient_spec/patient_manage.cy.ts index c25677d9e8b..00756f832f6 100644 --- a/cypress/e2e/patient_spec/patient_manage.cy.ts +++ b/cypress/e2e/patient_spec/patient_manage.cy.ts @@ -2,13 +2,11 @@ import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientConsultationPage } from "../../pageobject/Patient/PatientConsultation"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; -import PatientPrescription from "../../pageobject/Patient/PatientPrescription"; describe("Patient", () => { const loginPage = new LoginPage(); const patientPage = new PatientPage(); const patientConsultationPage = new PatientConsultationPage(); - const patientPrescription = new PatientPrescription(); before(() => { loginPage.loginAsDisctrictAdmin(); @@ -45,19 +43,6 @@ describe("Patient", () => { cy.verifyNotification("Note added successfully"); }); - it("Edit prescription for an already created patient", () => { - patientPage.visitPatient("Dummy Patient 4"); - patientPrescription.visitEditPrescriptionPage(); - patientPrescription.clickAddPrescription(); - patientPrescription.interceptMedibase(); - patientPrescription.selectMedicinebox(); - patientPrescription.selectMedicine("DOLO"); - patientPrescription.enterDosage("4"); - patientPrescription.selectDosageFrequency("Twice daily"); - cy.submitButton("Submit"); - cy.verifyNotification("Medicine prescribed"); - }); - afterEach(() => { cy.saveLocalStorage(); }); diff --git a/cypress/e2e/patient_spec/patient_prescription.cy.ts b/cypress/e2e/patient_spec/patient_prescription.cy.ts new file mode 100644 index 00000000000..3cf5a1ba5aa --- /dev/null +++ b/cypress/e2e/patient_spec/patient_prescription.cy.ts @@ -0,0 +1,49 @@ +import PatientPrescription from "../../pageobject/Patient/PatientPrescription"; +import LoginPage from "../../pageobject/Login/LoginPage"; +import { PatientPage } from "../../pageobject/Patient/PatientCreation"; + +const patientPrescription = new PatientPrescription(); +const loginPage = new LoginPage(); +const patientPage = new PatientPage(); + +describe("Patient Medicine Administration", () => { + before(() => { + loginPage.loginAsDisctrictAdmin(); + cy.saveLocalStorage(); + }); + + beforeEach(() => { + cy.restoreLocalStorage(); + cy.clearLocalStorage(/filters--.+/); + cy.awaitUrl("/patients"); + }); + + it("Add a new medicine for a patient and verify the duplicate medicine validation", () => { + patientPage.visitPatient("Dummy Patient 4"); + patientPrescription.visitMedicineTab(); + patientPrescription.clickAddPrescription(); + patientPrescription.interceptMedibase(); + patientPrescription.selectMedicinebox(); + patientPrescription.selectMedicine("DOLO"); + patientPrescription.enterDosage("4"); + patientPrescription.selectDosageFrequency("Twice daily"); + cy.submitButton("Submit"); + cy.verifyNotification("Medicine prescribed"); + cy.closeNotification(); + // verify the duplicate medicine error message + patientPrescription.clickAddPrescription(); + patientPrescription.interceptMedibase(); + patientPrescription.selectMedicinebox(); + patientPrescription.selectMedicine("DOLO"); + patientPrescription.enterDosage("4"); + patientPrescription.selectDosageFrequency("Twice daily"); + cy.submitButton("Submit"); + cy.verifyNotification( + "Medicine - This medicine is already prescribed to this patient. Please discontinue the existing prescription to prescribe again.", + ); + }); + + afterEach(() => { + cy.saveLocalStorage(); + }); +}); diff --git a/cypress/pageobject/Patient/PatientPrescription.ts b/cypress/pageobject/Patient/PatientPrescription.ts index 5c5c64483e4..dc4163e4823 100644 --- a/cypress/pageobject/Patient/PatientPrescription.ts +++ b/cypress/pageobject/Patient/PatientPrescription.ts @@ -12,13 +12,13 @@ export class PatientPrescription { selectMedicine(medicine: string) { cy.searchAndSelectOption( "div#medicine_object input[placeholder='Select'][role='combobox']", - medicine + medicine, ); } selectMedicinebox() { cy.get( - "div#medicine_object input[placeholder='Select'][role='combobox']" + "div#medicine_object input[placeholder='Select'][role='combobox']", ).click(); } @@ -37,21 +37,21 @@ export class PatientPrescription { clickReturnToDashboard() { cy.verifyAndClickElement( "[data-testid='return-to-patient-dashboard']", - "Return to Patient Dashboard" + "Return to Patient Dashboard", ); } discontinuePreviousPrescription() { cy.intercept( "POST", - "**/api/v1/consultation/*/prescriptions/*/discontinue/" + "**/api/v1/consultation/*/prescriptions/*/discontinue/", ).as("deletePrescription"); cy.get("button").contains("Discontinue").click(); cy.get("#submit").contains("Discontinue").click(); cy.wait("@deletePrescription").its("response.statusCode").should("eq", 200); } - visitEditPrescriptionPage() { + visitMedicineTab() { cy.get("#consultation_tab_nav").scrollIntoView(); cy.get("#consultation_tab_nav").contains("Medicines").click(); cy.get("a[href='prescriptions']").first().click(); From 9a1c3372f7c3a3154cafc96186788c01c6152e3e Mon Sep 17 00:00:00 2001 From: Keshav Malik <91189139+Keshav-0907@users.noreply.github.com> Date: Tue, 7 May 2024 14:30:50 +0530 Subject: [PATCH 09/30] Fix : Minimum value in forms should be greater than 0 (#7273) * Triage Form Fix * Added Validation for Negative Values in forms * Update src/Components/Facility/ConsultationForm.tsx Co-authored-by: Khavin Shankar * fix lint --------- Co-authored-by: Ashesh <3626859+Ashesh3@users.noreply.github.com> Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Co-authored-by: Rithvik Nishad Co-authored-by: Khavin Shankar Co-authored-by: Rithvik Nishad --- src/Components/Facility/ConsultationForm.tsx | 12 +++++++ src/Components/Facility/TriageForm.tsx | 36 ++++++++++++++++++++ src/Components/Patient/PatientRegister.tsx | 10 ++++++ 3 files changed, 58 insertions(+) diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index e0c79823434..e4b3f4a195f 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -642,6 +642,18 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { } return; } + case "weight": + case "height": { + if (state.form.suggestion !== "DD") { + const value = state.form[field]; + if (!value || parseFloat(value) <= 0) { + errors[field] = `Please enter a valid ${field}`; + invalidForm = true; + break; + } + } + return; + } default: return; diff --git a/src/Components/Facility/TriageForm.tsx b/src/Components/Facility/TriageForm.tsx index 5cf76fbda49..1efe22e66a4 100644 --- a/src/Components/Facility/TriageForm.tsx +++ b/src/Components/Facility/TriageForm.tsx @@ -102,6 +102,42 @@ export const TriageForm = ({ facilityId, id }: Props) => { invalidForm = true; } return; + case "num_patients_visited": + if (state.form[field] < 0) { + errors[field] = + "Number of patients visited must be greater than or equal to 0"; + invalidForm = true; + } + return; + case "num_patients_home_quarantine": + if (state.form[field] < 0) { + errors[field] = + "Number of patients in Home Qurantine must be greater than or equal to 0"; + invalidForm = true; + } + return; + case "num_patients_isolation": + if (state.form[field] < 0) { + errors[field] = + "Number of patients in Isolation must be greater than or equal to 0"; + invalidForm = true; + } + return; + case "num_patient_referred": + if (state.form[field] < 0) { + errors[field] = + "Number of patients referred must be greater than or equal to 0"; + invalidForm = true; + } + return; + case "num_patient_confirmed_positive": + if (state.form[field] < 0) { + errors[field] = + "Number of patients confirmed positive must be greater than or equal to 0"; + invalidForm = true; + } + return; + default: return; } diff --git a/src/Components/Patient/PatientRegister.tsx b/src/Components/Patient/PatientRegister.tsx index dea0484a67c..67032abede8 100644 --- a/src/Components/Patient/PatientRegister.tsx +++ b/src/Components/Patient/PatientRegister.tsx @@ -649,6 +649,16 @@ export const PatientRegister = (props: PatientRegisterProps) => { errors[field] = "Please select a blood group"; } return; + case "number_of_primary_contacts": + if (form[field] < 0) { + errors[field] = "Number of primary contacts cannot be negative"; + } + return; + case "number_of_secondary_contacts": + if (form[field] < 0) { + errors[field] = "Number of secondary contacts cannot be negative"; + } + return; case "is_vaccinated": if (form.is_vaccinated === "true") { From 02d9b90a59d08774f65db2843229326bb145d28b Mon Sep 17 00:00:00 2001 From: Vibhu Chandransh Bhanot <66901877+Vibhu1710@users.noreply.github.com> Date: Tue, 7 May 2024 14:31:25 +0530 Subject: [PATCH 10/30] #7308 fix : use "hidden" css property to toggle b/w Login & Forgot Password (#7323) * fix : use "hidden" css property to toggle b/w Login & Forgot Password page * suggestions from code review --------- Co-authored-by: Vibhu1710 Co-authored-by: rithviknishad --- src/Components/Auth/Login.tsx | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Components/Auth/Login.tsx b/src/Components/Auth/Login.tsx index b3d2fef8d31..a74969fbfa4 100644 --- a/src/Components/Auth/Login.tsx +++ b/src/Components/Auth/Login.tsx @@ -13,6 +13,7 @@ import ReactMarkdown from "react-markdown"; import rehypeRaw from "rehype-raw"; import { useAuthContext } from "../../Common/hooks/useAuthUser"; import FiltersCache from "../../Utils/FiltersCache"; +import { classNames } from "../../Utils/utils"; export const Login = (props: { forgot?: boolean }) => { const { signIn } = useAuthContext(); @@ -276,12 +277,10 @@ export const Login = (props: { forgot?: boolean }) => {
{t("auth_login_title")} @@ -353,12 +352,10 @@ export const Login = (props: { forgot?: boolean }) => {