diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b49a749e24..d001bcf4b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,4 +39,3 @@ jobs: - name: Build OpenELIS-Global2 run: mvn clean install -Dspotless.check.skip=true - diff --git a/.github/workflows/frontend-qa.yml b/.github/workflows/frontend-qa.yml index 2029de1497..296d8625ad 100644 --- a/.github/workflows/frontend-qa.yml +++ b/.github/workflows/frontend-qa.yml @@ -8,9 +8,8 @@ on: env: DOCKER_NAME: ${{ vars.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}-frontend - -jobs: +jobs: build-prod-frontend-image: runs-on: ubuntu-latest permissions: @@ -38,8 +37,7 @@ jobs: with: context: ./frontend file: ./frontend/Dockerfile.prod - push: false - + push: false build-and-run-qa-tests: runs-on: ubuntu-latest @@ -50,12 +48,8 @@ jobs: repository: ${{github.repository}} submodules: recursive - - name: Run OpenELS image - run: docker compose -f build.docker-compose.yml up -d - - - name: Sleep for 2 minutes - run: sleep 2m - shell: bash + - name: Run OpenELIS image + run: docker compose -f build.docker-compose.yml up -d --build --wait --wait-timeout 600 - name: Set up Node.js uses: actions/setup-node@v3 @@ -73,3 +67,10 @@ jobs: - name: Run Frontend Qa Workflow run: npx cypress run –headless working-directory: frontend + + - name: Dump docker logs on failure + if: failure() + uses: jwalton/gh-docker-logs@v2 + with: + # Only show last 100 lines of each + tail: "100" diff --git a/.github/workflows/publish-and-test.yml b/.github/workflows/publish-and-test.yml index dd5ffa4b36..7f34437bd6 100644 --- a/.github/workflows/publish-and-test.yml +++ b/.github/workflows/publish-and-test.yml @@ -138,13 +138,12 @@ jobs: - name: Build and push Docker image uses: docker/build-push-action@v5 with: - platforms: linux/amd64,linux/arm64 context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - # cache-from: type=registry,ref=${{ env.DOCKER_TEST_NAME }}:buildcache-test - # cache-to: type=registry,ref=${{ env.DOCKER_TEST_NAME }}:buildcache-test,mode=max + # cache-from: type=registry,ref=${{ env.DOCKER_TEST_NAME }}:buildcache + cache-to: type=registry,ref=${{ env.DOCKER_TEST_NAME }}:buildcache,mode=max build-args: SKIP_SPOTLESS=true build-and-push-test-image-frontend: @@ -186,25 +185,21 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=registry,ref=${{ env.DOCKER_TEST_NAME }}-frontend:buildcache-test - cache-to: type=registry,ref=${{ env.DOCKER_TEST_NAME }}-frontend:buildcache-test,mode=max + # cache-from: type=registry,ref=${{ env.DOCKER_TEST_NAME }}-frontend:buildcache + cache-to: type=registry,ref=${{ env.DOCKER_TEST_NAME }}-frontend:buildcache,mode=max run-e2e-qa: needs: [build-and-push-test-image-backend, build-and-push-test-image-frontend] runs-on: ubuntu-latest steps: - - name: Sleep for 2 minutes - run: sleep 2m - shell: bash - - name: Checkout OpenELIS-Global2 uses: actions/checkout@v4 with: repository: ${{github.repository}} - - name: Run OpenELS image - run: docker compose -f test.docker-compose.yml up -d + - name: Run OpenELIS image + run: docker compose -f test.docker-compose.yml up -d --build --wait --wait-timeout 300 - name: Cypress run uses: cypress-io/github-action@v6 @@ -214,6 +209,13 @@ jobs: CYPRESS_STARTUP_WAIT_MILLISECONDS: 300000 CYPRESS_VIDEO: false + - name: Dump docker logs on failure + if: failure() + uses: jwalton/gh-docker-logs@v2 + with: + # Only show last 100 lines of each + tail: "100" + build-and-push-image-backend: needs: [run-e2e-qa] runs-on: ubuntu-latest @@ -251,13 +253,12 @@ jobs: - name: Build and push Docker image uses: docker/build-push-action@v5 with: - platforms: linux/amd64,linux/arm64 context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - # cache-from: type=registry,ref=${{ env.DOCKER_TEST_NAME }}:buildcache-prod - # cache-to: type=registry,ref=${{ env.DOCKER_TEST_NAME }}:buildcache-prod,mode=max + cache-from: type=registry,ref=${{ env.DOCKER_TEST_NAME }}:buildcache + cache-to: type=registry,ref=${{ env.DOCKER_TEST_NAME }}:buildcache,mode=max build-args: SKIP_SPOTLESS=true build-and-push-image-frontend: @@ -300,5 +301,5 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=registry,ref=${{ env.DOCKER_TEST_NAME }}-frontend:buildcache-prod - cache-to: type=registry,ref=${{ env.DOCKER_TEST_NAME }}-frontend:buildcache-prod,mode=max + cache-from: type=registry,ref=${{ env.DOCKER_TEST_NAME }}-frontend:buildcache + cache-to: type=registry,ref=${{ env.DOCKER_TEST_NAME }}-frontend:buildcache,mode=max diff --git a/Dockerfile b/Dockerfile index 616c735576..23f545b1cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -91,7 +91,12 @@ RUN groupadd tomcat; \ chmod g-w,o-rwx $CATALINA_HOME/conf/logging.properties; \ chmod g-w,o-rwx $CATALINA_HOME/conf/server.xml; \ chmod g-w,o-rwx $CATALINA_HOME/conf/tomcat-users.xml; \ - chmod g-w,o-rwx $CATALINA_HOME/conf/web.xml + chmod g-w,o-rwx $CATALINA_HOME/conf/web.xml; \ + mkdir -p /var/lib/openelis-global/logs/; \ + chown -R tomcat_admin:tomcat /var/lib/openelis-global/logs/;\ + mkdir -p /var/lib/openelis-global/properties/; \ + chown -R tomcat_admin:tomcat /var/lib/openelis-global/properties/; + COPY install/openelis_healthcheck.sh /healthcheck.sh RUN chown tomcat_admin:tomcat /healthcheck.sh; \ diff --git a/build.docker-compose.yml b/build.docker-compose.yml index 250b7fad6f..2f70bed6df 100644 --- a/build.docker-compose.yml +++ b/build.docker-compose.yml @@ -50,7 +50,6 @@ services: networks: default: ipv4_address: 172.20.1.121 - environment: - DEFAULT_PW=adminADMIN! - TZ=Africa/Nairobi @@ -64,10 +63,18 @@ services: secrets: - source: datasource.password - source: common.properties + healthcheck: + test: ["CMD", "/healthcheck.sh"] + timeout: 10s + interval: 30s + retries: 3 + start_period: 2m fhir.openelis.org: container_name: external-fhir-api - image: hapiproject/hapi:v6.6.0-tomcat + build: + context: ./fhir + dockerfile: ./Dockerfile depends_on: - database - certs @@ -110,8 +117,11 @@ services: - CHOKIDAR_USEPOLLING=true tty: true + proxy: - image: nginx:1.15-alpine + build: + context: ./nginx-proxy + dockerfile: ./Dockerfile container_name: openelisglobal-proxy ports: - 80:80 diff --git a/frontend/cypress.config.js b/frontend/cypress.config.js index 6c11da3c32..f5b9f83351 100755 --- a/frontend/cypress.config.js +++ b/frontend/cypress.config.js @@ -4,6 +4,7 @@ module.exports = defineConfig({ defaultCommandTimeout: 8000, viewportWidth: 1200, viewportHeight: 700, + watchForFileChanges: false, e2e: { setupNodeEvents(on, config) { // implement node event listeners here @@ -13,7 +14,10 @@ module.exports = defineConfig({ "cypress/e2e/orderEntity.cy.js", "cypress/e2e/workplan.cy.js", "cypress/e2e/nonConform.cy.js", + "cypress/e2e/result.cy.js", + "cypress/e2e/validation.cy.js", "cypress/e2e/modifyOrder.cy.js", + "cypress/e2e/report.cy.js", "cypress/e2e/batchOrderEntry.cy.js", "cypress/e2e/dashboard.cy.js", ]; diff --git a/frontend/cypress/e2e/report.cy.js b/frontend/cypress/e2e/report.cy.js new file mode 100644 index 0000000000..97018afb8c --- /dev/null +++ b/frontend/cypress/e2e/report.cy.js @@ -0,0 +1,307 @@ +import LoginPage from "../pages/LoginPage"; + +let homePage = null; +let loginPage = null; +let reportPage = null; + +before("login", () => { + loginPage = new LoginPage(); + loginPage.visit(); +}); + +describe("Routine Reports", function () { + it("User Visits Routine Reports", function () { + homePage = loginPage.goToHomePage(); + reportPage = homePage.goToRoutineReports(); + }); + it("User Visits Patient Status Report and checks for Respective Forms", () => { + reportPage.navigateToSection(1, 1); + reportPage.validatePageHeader("Patient Status Report"); + + reportPage.toggleAccordionPatient(2); + reportPage.validateFieldVisibility("#patientId"); + reportPage.validateFieldVisibility("#local_search"); + reportPage.toggleAccordionPatient(2); + + reportPage.toggleAccordion(3); + reportPage.validateFieldVisibility("#from"); + reportPage.validateFieldVisibility("#to"); + reportPage.toggleAccordion(3); + + reportPage.toggleAccordion(6); + reportPage.validateFieldVisibility('[data-cy="dateTypeDropdown"]'); + reportPage.validateFieldVisibility( + ".cds--date-picker-input__wrapper > #startDate", + ); + reportPage.validateButtonVisible( + ":nth-child(7) > :nth-child(2) > .cds--btn", + ); + }); + + it("Should Visit Statistics Reports", () => { + reportPage.visitRoutineReports(); + reportPage.navigateToSection(2, 1); + reportPage.validatePageHeader("Statistics Report"); + + reportPage.checkAllCheckboxes( + 2, + 11, + ":nth-child(1) > .cds--sm\\:col-span-4 > :nth-child(2)", + ); + reportPage.validateFieldVisibility( + ':nth-child(1) > .cds--sm\\:col-span-4 > :nth-child(2) > :nth-child(1) input[type="checkbox"]', + ); + }); + + it('Within Statistic Should uncheck the "All" checkbox if any individual checkbox is unchecked', () => { + reportPage.checkAllCheckboxes( + 2, + 11, + ":nth-child(1) > .cds--sm\\:col-span-4 > :nth-child(2)", + ); + reportPage.validateAllCheckBox("not.be.checked"); + reportPage.uncheckCheckbox( + 2, + ":nth-child(1) > .cds--sm\\:col-span-4 > :nth-child(2)", + ); + reportPage.validateAllCheckBox("not.be.checked"); + reportPage.validateFieldVisibility( + ':nth-child(1) > .cds--sm\\:col-span-4 > :nth-child(2) > :nth-child(1) input[type="checkbox"]', + ); + }); + + it('Should check/uncheck "All" checkbox for priority', () => { + reportPage.checkAllCheckboxes(2, 6, ".inlineDiv"); + reportPage.uncheckCheckbox(2, ".inlineDiv"); + reportPage.validateButtonVisible( + ":nth-child(3) > .cds--sm\\:col-span-4 > :nth-child(2) > :nth-child(1) > .cds--checkbox-label", + ); + }); + + it("should check for print button", () => { + reportPage.validateButtonVisible(":nth-child(6) > .cds--btn"); + }); + + it("Visits Summary of all tests", () => { + reportPage.visitRoutineReports(); + reportPage.navigateToSection(2, 2); + reportPage.validatePageHeader("Test Report Summary"); + reportPage.validateButtonDisabled(".cds--form > :nth-child(3) > .cds--btn"); + reportPage.typeInDatePicker( + ".cds--date-picker-input__wrapper > #startDate", + "01/02/2023", + ); + reportPage.validateButtonVisible(".cds--form > :nth-child(3) > .cds--btn"); + }); + + it("Visits HIV Test Summary and validates", () => { + reportPage.visitRoutineReports(); + reportPage.navigateToSection(2, 3); + reportPage.validateButtonDisabled(".cds--form > :nth-child(3) > .cds--btn"); + reportPage.typeInDatePicker( + ".cds--date-picker-input__wrapper > #startDate", + "01/02/2023", + ); + reportPage.validateButtonVisible(".cds--form > :nth-child(3) > .cds--btn"); + }); + + it("Visits Rejection Report and validates", () => { + reportPage.visitRoutineReports(); + reportPage.navigateToSection(3, 1); + reportPage.validatePageHeader("Rejection Report"); + reportPage.validateButtonDisabled(".cds--form > :nth-child(3) > .cds--btn"); + reportPage.typeInDatePicker( + ".cds--date-picker-input__wrapper > #startDate", + "01/02/2023", + ); + reportPage.validateButtonVisible(".cds--form > :nth-child(3) > .cds--btn"); + }); + + it("Visits Activity Report By Test Type", () => { + reportPage.visitRoutineReports(); + reportPage.navigateToSection(4, 1); + reportPage.validatePageHeader("Activity report By test"); + reportPage.validateButtonDisabled(".cds--form > :nth-child(3) > .cds--btn"); + reportPage.typeInDatePicker( + ".cds--date-picker-input__wrapper > #startDate", + "01/02/2023", + ); + reportPage.selectDropdown("#type", "Amylase(Serum)"); + reportPage.validateButtonVisible(".cds--form > :nth-child(3) > .cds--btn"); + }); + + it("Visits Activity Report By Panel Type", () => { + reportPage.visitRoutineReports(); + reportPage.navigateToSection(4, 2); + reportPage.validatePageHeader("Activity report By Panel"); + reportPage.validateButtonDisabled(".cds--form > :nth-child(3) > .cds--btn"); + reportPage.typeInDatePicker( + ".cds--date-picker-input__wrapper > #startDate", + "01/02/2023", + ); + reportPage.selectDropdown("#type", "NFS"); + reportPage.validateButtonVisible(".cds--form > :nth-child(3) > .cds--btn"); + }); + + it("Visits Activity Report By Unit", () => { + reportPage.visitRoutineReports(); + reportPage.navigateToSection(4, 3); + reportPage.validatePageHeader("Activity report By Test Section"); + reportPage.validateButtonDisabled(".cds--form > :nth-child(3) > .cds--btn"); + reportPage.typeInDatePicker( + ".cds--date-picker-input__wrapper > #startDate", + "01/02/2023", + ); + reportPage.selectDropdown("#type", "Biochemistry"); + reportPage.validateButtonVisible(".cds--form > :nth-child(3) > .cds--btn"); + }); + + it("Visits Referred Out Test Report", () => { + reportPage.visitRoutineReports(); + reportPage.navigateToSection(5, 1); + reportPage.validatePageHeader("External Referrals Report"); + reportPage.typeInDatePicker( + ".cds--date-picker-input__wrapper > #startDate", + "01/02/2023", + ); + reportPage.typeInDatePicker( + ".cds--date-picker-input__wrapper > #endDate", + "02/02/2023", + ); + reportPage.selectDropdown("#locationcode", "CEDRES"); + reportPage.validateButtonVisible(":nth-child(4) > .cds--btn"); + }); + + it("Visits Non Conformity Report By Date", () => { + reportPage.visitRoutineReports(); + reportPage.navigateToSection(6, 1); + reportPage.validatePageHeader("Non ConformityReport by Date"); + reportPage.validateButtonDisabled(".cds--form > :nth-child(3) > .cds--btn"); + reportPage.typeInDatePicker( + ".cds--date-picker-input__wrapper > #startDate", + "01/02/2023", + ); + reportPage.validateButtonVisible(".cds--form > :nth-child(3) > .cds--btn"); + }); + + it("Visits Non Conformity Report By Unit", () => { + reportPage.visitRoutineReports(); + reportPage.navigateToSection(6, 2); + reportPage.validatePageHeader("Non Conformity Report by Unit and Reason"); + reportPage.validateButtonDisabled(".cds--form > :nth-child(3) > .cds--btn"); + reportPage.typeInDatePicker( + ".cds--date-picker-input__wrapper > #startDate", + "01/02/2023", + ); + reportPage.validateButtonVisible(".cds--form > :nth-child(3) > .cds--btn"); + }); + + it("Visits Export Routine CSV", () => { + reportPage.visitRoutineReports(); + reportPage.navigateToSection(9, 1); + reportPage.validatePageHeader("Export Routine CSV file"); + reportPage.validateButtonDisabled(".cds--form > :nth-child(3) > .cds--btn"); + reportPage.typeInDatePicker( + ".cds--date-picker-input__wrapper > #startDate", + "01/02/2023", + ); + reportPage.validateButtonVisible(".cds--form > :nth-child(3) > .cds--btn"); + }); +}); + +describe("Study Reports", function () { + it("User Visits Study Reports", function () { + homePage = loginPage.goToHomePage(); + reportPage = homePage.goToStudyReports(); + }); + + it("should visit ARV Initial Version 1 and verify the button state", () => { + reportPage.visitARVInitialVersion1(); + }); + + it("should visit ARV Initial Version 2 and verify the header and button state", () => { + reportPage.visitARVInitialVersion2(); + }); + + it("should visit ARV Follow-Up Version 1 and verify the header and button state", () => { + reportPage.visitARVFollowUpVersion1(); + }); + + it("should visit ARV Follow-Up Version 2 and verify the header and button state", () => { + reportPage.visitARVFollowUpVersion2(); + }); + + it("should visit ARV Follow-Up Version 3 and verify the header and button state", () => { + reportPage.visitARVFollowUpVersion3(); + }); + + it("should visit EID Version 1 and verify the accordion items and button state", () => { + reportPage.visitEIDVersion1(); + }); + + it("should visit EID Version 2 and verify the header and button state", () => { + reportPage.visitEIDVersion2(); + }); + + it("should visit VL Version and verify the accordion items and button state", () => { + reportPage.visitVLVersion(); + }); + + it("should visit Intermediate Version 1 and verify the header and button state", () => { + reportPage.visitIntermediateVersion1(); + }); + + it("should visit Intermediate Version 2 and verify the header and button state", () => { + reportPage.visitIntermediateVersion2(); + }); + + it("should visit Intermediate By Service and verify the input fields and button state", () => { + reportPage.visitIntermediateByService(); + }); + + it("should visit Special Request and verify the header and button state", () => { + reportPage.visitSpecialRequest(); + }); + + it("should visit Collected ARV Patient Report and verify the header and button state", () => { + reportPage.visitCollectedARVPatientReport(); + }); + + it("should visit Associated Patient Report and verify the header and button state", () => { + reportPage.visitAssociatedPatientReport(); + }); + + it("should visit Non-Conformity Report By Date and verify the header and button state", () => { + reportPage.visitNonConformityReportByDate(); + }); + + it("should visit Non-Conformity Report By Unit and Reason and verify the header and button state", () => { + reportPage.visitNonConformityReportByUnitAndReason(); + }); + + it("should visit Non-Conformity Report By Lab No and verify the header and button state", () => { + reportPage.visitNonConformityReportByLabNo(); + }); + + it("should visit Non-Conformity Report By Notification and verify the button state", () => { + reportPage.visitNonConformityReportByNotification(); + }); + + it("should visit Non-Conformity Report Follow-Up Required and verify the header and button state", () => { + reportPage.visitNonConformityReportFollowUpRequired(); + }); + + it("should visit General Report In Export By Date and select options", () => { + reportPage.visitGeneralReportInExportByDate(); + }); + + it("User Visits Audit Trail Report And Validates", function () { + reportPage.visitStudyReports(); + reportPage.visitAuditTrailReport(); + reportPage.verifyHeaderText("section > h3", "Audit Trail"); + cy.fixture("EnteredOrder").then((order) => { + reportPage.typeInField("labNo", order.labNo); + }); + reportPage.validateAudit(); + }); +}); diff --git a/frontend/cypress/e2e/result.cy.js b/frontend/cypress/e2e/result.cy.js new file mode 100644 index 0000000000..c42053f533 --- /dev/null +++ b/frontend/cypress/e2e/result.cy.js @@ -0,0 +1,285 @@ +import LoginPage from "../pages/LoginPage"; +import HomePage from "../pages/HomePage"; +import Result from "../pages/ResultsPage"; +import PatientEntryPage from "../pages/PatientEntryPage"; + +let homePage = null; +let loginPage = null; +let result = null; +let patientPage = new PatientEntryPage(); + +before("login", () => { + loginPage = new LoginPage(); + loginPage.visit(); +}); + +describe("Result By Unit", function () { + before("navigate to Result By Unit", function () { + homePage = loginPage.goToHomePage(); + result = homePage.goToResultsByUnit(); + }); + + it("User visits Results Page", function () { + cy.fixture("result").then((res) => { + result.getResultTitle().should("contain.text", res.pageTitle); + }); + }); + + it("Should Search by Unit", function () { + cy.fixture("workplan").then((order) => { + result.selectUnitType(order.unitType); + }); + }); + + it("should accept the sample, refer the sample, and save the result", function () { + cy.fixture("result").then((res) => { + result.acceptSample(); + result.expandSampleDetails(); + result.selectTestMethod(0, res.pcrTestMethod); + cy.get(":nth-child(3) > .cds--form-item > .cds--checkbox-label").click(); + result.referSample(0, res.testNotPerformed, res.cedres); + result.setResultValue(0, res.positiveResult); + result.submitResults(); + }); + }); +}); + +describe("Result By Patient", function () { + before("navigate to Result By Patient", function () { + result = homePage.goToResultsByPatient(); + }); + + it("User visits Results Page", function () { + cy.fixture("result").then((res) => { + result.getResultTitle().should("contain.text", res.pageTitle); + }); + }); + + it("Should search Patient By First and LastName and validate", function () { + cy.wait(1000); + cy.fixture("Patient").then((patient) => { + patientPage.searchPatientByFirstAndLastName( + patient.firstName, + patient.lastName, + ); + patientPage.getFirstName().should("have.value", patient.firstName); + patientPage.getLastName().should("have.value", patient.lastName); + patientPage.getLastName().should("not.have.value", patient.inValidName); + patientPage.clickSearchPatientButton(); + patientPage.validatePatientSearchTable( + patient.firstName, + patient.inValidName, + ); + }); + cy.reload(); + }); + + it("should search patient By PatientId and validate", function () { + cy.wait(500); + cy.fixture("Patient").then((patient) => { + patientPage.searchPatientByPatientId(patient.nationalId); + patientPage.clickSearchPatientButton(); + patientPage.validatePatientSearchTable( + patient.firstName, + patient.inValidName, + ); + }); + cy.reload(); + }); + + it("should search patient By Lab Number and validate", function () { + cy.wait(500); + cy.fixture("EnteredOrder").then((patient) => { + cy.get("#labNumber").type(patient.labNo); + patientPage.clickSearchPatientButton(); + }); + }); + + it("Should be able to search by respective patient and accept the result", function () { + cy.wait(1000); + result.selectPatient(); + cy.fixture("result").then((res) => { + result.acceptResult(); + result.expandSampleDetails(); + result.selectTestMethod(0, res.stainTestMethod); + result.submitResults(); + }); + }); +}); + +describe("Result By Order", function () { + before("navigate to Result By Order", function () { + homePage = loginPage.goToHomePage(); + result = homePage.goToResultsByOrder(); + }); + + it("User visits Results Page", function () { + cy.fixture("result").then((res) => { + result.getResultTitle().should("contain.text", res.pageTitle); + }); + }); + + it("Should Search by Accession Number", function () { + cy.fixture("EnteredOrder").then((order) => { + cy.get("#accessionNumber").type(order.labNo); + }); + cy.get(":nth-child(4) > #submit").click(); + }); + + it("should accept the sample and save the result", function () { + cy.fixture("result").then((res) => { + result.acceptSample(); + result.expandSampleDetails(); + result.selectTestMethod(0, res.stainTestMethod); + result.submitResults(); + }); + }); +}); + +describe("Result By Referred Out Tests", function () { + before("navigate to Result By Referred Out Tests", function () { + homePage = loginPage.goToHomePage(); + result = homePage.goToResultsForRefferedOut(); + }); + + it("User visits Reffered out Page", function () { + cy.fixture("result").then((res) => { + result.getResultTitle().should("contain.text", res.referralPageTitle); + }); + }); + + it("should search Referrals By Patient and validate", function () { + cy.fixture("Patient").then((patient) => { + patientPage.searchPatientByPatientId(patient.nationalId); + patientPage.searchPatientByFirstAndLastName( + patient.firstName, + patient.lastName, + ); + patientPage.getFirstName().should("have.value", patient.firstName); + patientPage.getLastName().should("have.value", patient.lastName); + patientPage.clickSearchPatientButton(); + patientPage.validatePatientSearchTable( + patient.firstName, + patient.inValidName, + ); + }); + }); + + it("should click respective patient and search for referred out tests", function () { + result.selectPatient(); + result.search(); + }); + + it("should validate the results", function () { + cy.wait(1000); + cy.fixture("Patient").then((patient) => { + result.validatePatientResult(patient); + }); + cy.reload(); + }); + + it("should search Referrals By Test Unit and validate", function () { + cy.fixture("workplan").then((res) => { + cy.get("#testnames-input").type(res.testName); + cy.get("#testnames-item-0-item").click(); + cy.get(":nth-child(15) > .cds--btn").click({ force: true }); + }); + //update in UI elements + // cy.fixture("result").then((res) => { + // cy.get("tbody > tr > :nth-child(8)").should( + // "contain.text", + // res.westernBlotHiv, + // ); + // }); + cy.reload(); + }); + + it("should search Referrals By LabNumber and validate", function () { + cy.fixture("EnteredOrder").then((order) => { + cy.get("#labNumberInput").type(order.labNo); + }); + cy.get(":nth-child(4) > .cds--lg\\:col-span-4 > .cds--btn") + .should("be.visible") + .click(); + //update in UI elements + // cy.fixture("EnteredOrder").then((patient) => { + // cy.get("tbody > tr > :nth-child(3)").should( + // "contain.text", + // patient.labNo, + // ); + // }); + }); + //commented due to UI changes + // it("should select the respecting referred test and print the selected patient reports", function () { + // result.selectRefferedTest(); + // result.printReport(); + // }); +}); + +describe("Result By Range Of Order", function () { + before("navigate to Result By Range Of Order", function () { + homePage = loginPage.goToHomePage(); + result = homePage.goToResultsByRangeOrder(); + }); + + it("User visits Results Page", function () { + cy.fixture("result").then((res) => { + result.getResultTitle().should("contain.text", res.pageTitle); + }); + }); + + it("Should Enter Lab Number and perform Search", function () { + cy.fixture("EnteredOrder").then((order) => { + cy.get("#startLabNo").type(order.labNo); + }); + cy.get(":nth-child(5) > #submit").click(); + }); + + it("Should Accept And Save the result", function () { + cy.wait(1000); + cy.fixture("result").then((res) => { + result.acceptSample(); + result.expandSampleDetails(); + result.selectTestMethod(0, res.eiaTestMethod); + result.submitResults(); + }); + }); +}); + +describe("Result By Test And Status", function () { + before("navigate to Result By Test And Status", function () { + homePage = loginPage.goToHomePage(); + result = homePage.goToResultsByTestAndStatus(); + }); + + it("User visits Results Page", function () { + cy.fixture("result").then((res) => { + result.getResultTitle().should("contain.text", res.pageTitle); + }); + }); + + it("Should select testName, analysis status, and perform Search", function () { + cy.fixture("workplan").then((order) => { + result.selectTestName(order.testName); + }); + cy.fixture("result").then((res) => { + result.selectAnalysisStatus(res.acceptedStatus); + result.searchByTest(); + }); + }); + + it("Should Validate And accept the result", function () { + cy.fixture("workplan").then((order) => { + cy.get("#cell-testName-0 > .sampleInfo").should( + "contain.text", + order.testName, + ); + }); + cy.fixture("result").then((res) => { + result.acceptSample(); + result.expandSampleDetails(); + result.selectTestMethod(0, res.eiaTestMethod); + result.submitResults(); + }); + }); +}); diff --git a/frontend/cypress/e2e/validation.cy.js b/frontend/cypress/e2e/validation.cy.js new file mode 100644 index 0000000000..3e0f947f6a --- /dev/null +++ b/frontend/cypress/e2e/validation.cy.js @@ -0,0 +1,72 @@ +import LoginPage from "../pages/LoginPage"; +import HomePage from "../pages/HomePage"; +import PatientEntryPage from "../pages/PatientEntryPage"; +import Validation from "../pages/Validation"; + +let homePage = null; +let loginPage = null; +let validation = null; +let patientPage = new PatientEntryPage(); + +before("login", () => { + loginPage = new LoginPage(); + loginPage.visit(); +}); + +const navigateToValidationPage = (validationType) => { + homePage = loginPage.goToHomePage(); + validation = homePage[`goToValidationBy${validationType}`](); +}; + +describe("Validation By Routine", function () { + before("navigate to Validation Page", function () { + navigateToValidationPage("Routine"); + }); + + it("User visits Validation Page", function () { + validation.checkForHeading(); + }); + + it("Should Select Test Unit From Drop-Down And Validate", function () { + cy.fixture("workplan").then((order) => { + validation.selectTestUnit(order.unitType); + validation.validateTestUnit(order.testName); + }); + }); +}); + +describe("Validation By Order", function () { + before("navigate to Validation Page", function () { + navigateToValidationPage("Order"); + }); + + it("User visits Validation Page", function () { + validation.checkForHeading(); + }); + + it("Should Enter Lab Number, make a search and validate", function () { + cy.fixture("EnteredOrder").then((order) => { + validation.enterLabNumberAndSearch(order.labNo); + }); + }); +}); + +describe("Validation By Range Of Order", function () { + before("navigate to Validation Page", function () { + navigateToValidationPage("RangeOrder"); + }); + + it("User visits Validation Page", function () { + validation.checkForHeading(); + }); + + it("Should Enter Lab Number and perform a search", function () { + cy.fixture("EnteredOrder").then((order) => { + validation.enterLabNumberAndSearch(order.labNo); + }); + }); + + it("Should Save the results", function () { + validation.saveResults("Test Note"); + }); +}); diff --git a/frontend/cypress/fixtures/result.json b/frontend/cypress/fixtures/result.json new file mode 100644 index 0000000000..dc0bcbec8e --- /dev/null +++ b/frontend/cypress/fixtures/result.json @@ -0,0 +1,13 @@ +{ + "pageTitle": "Results", + "pcrTestMethod": "PCR", + "stainTestMethod": "STAIN", + "positiveResult": "Positive HIV1", + "referralPageTitle": "Referrals", + "westernBlotHiv": "Western blot HIV", + "acceptedStatus": "Accepted by technician", + "eiaTestMethod": "EIA", + "invalidTestMethod": "Invalid", + "testNotPerformed": "Test not performed", + "cedres": "CEDRES" +} diff --git a/frontend/cypress/pages/HomePage.js b/frontend/cypress/pages/HomePage.js index b076716ecc..dfedb13fc3 100755 --- a/frontend/cypress/pages/HomePage.js +++ b/frontend/cypress/pages/HomePage.js @@ -4,7 +4,13 @@ import OrderEntityPage from "./OrderEntityPage"; import ModifyOrderPage from "./ModifyOrderPage"; import WorkPlan from "./WorkPlan"; import NonConform from "./NonConformPage"; +import Result from "./ResultsPage"; +import Validation from "./Validation"; import BatchOrderEntry from "./BatchOrderEntryPage"; + +import RoutineReportPage from "./RoutineReportPage"; +import StudyReportPage from "./StudyReportPage"; + import DashBoardPage from "./DashBoard"; class HomePage { @@ -99,6 +105,80 @@ class HomePage { return new NonConform(); } + goToResultsByUnit() { + this.openNavigationMenu(); + cy.get("#menu_results").click(); + cy.get("#menu_results_logbook").click(); + return new Result(); + } + + goToResultsByOrder() { + this.openNavigationMenu(); + cy.get("#menu_results").click(); + cy.get("#menu_results_accession").click(); + return new Result(); + } + + goToResultsByPatient() { + this.openNavigationMenu(); + cy.get("#menu_results").click(); + cy.get("#menu_results_patient").click(); + return new Result(); + } + + goToResultsForRefferedOut() { + this.openNavigationMenu(); + cy.get("#menu_results").click(); + cy.get("#menu_results_referred ").click(); + return new Result(); + } + + goToResultsByRangeOrder() { + this.openNavigationMenu(); + cy.get("#menu_results").click(); + cy.get("#menu_results_range").click(); + return new Result(); + } + + goToResultsByTestAndStatus() { + this.openNavigationMenu(); + cy.get("#menu_results").click(); + cy.get("#menu_results_status").click(); + return new Result(); + } + + goToValidationByRoutine() { + this.openNavigationMenu(); + cy.get("#menu_resultvalidation").click(); + cy.get("#menu_resultvalidation_routine ").click(); + return new Validation(); + } + goToValidationByOrder() { + this.openNavigationMenu(); + cy.get("#menu_resultvalidation").click(); + cy.get("#menu_accession_validation ").click(); + return new Validation(); + } + goToValidationByRangeOrder() { + this.openNavigationMenu(); + cy.get("#menu_resultvalidation").click(); + cy.get("#menu_accession_validation_range ").click(); + return new Validation(); + } + + goToRoutineReports() { + this.openNavigationMenu(); + cy.get("#menu_reports").click(); + cy.get("#menu_reports_routine_nav").click(); + return new RoutineReportPage(); + } + goToStudyReports() { + this.openNavigationMenu(); + cy.get("#menu_reports").click(); + cy.get("#menu_reports_study_nav").click(); + return new StudyReportPage(); + } + goToPathologyDashboard() { this.openNavigationMenu(); cy.get("#menu_pathology_dropdown").click(); diff --git a/frontend/cypress/pages/ResultsPage.js b/frontend/cypress/pages/ResultsPage.js new file mode 100644 index 0000000000..75aa6a77c0 --- /dev/null +++ b/frontend/cypress/pages/ResultsPage.js @@ -0,0 +1,84 @@ +class Result { + getResultTitle() { + return cy.get("section > h3"); + } + + selectUnitType(unitType) { + cy.get("#unitType").select(unitType); + } + + acceptSample(index = 0) { + cy.get(`.cds--checkbox-label`).eq(index).click(); + } + + acceptResult() { + cy.get("#cell-accept-0 > .cds--form-item > .cds--checkbox-label").click(); + } + + expandSampleDetails(index = 0) { + cy.get(`[data-testid="expander-button-${index}"]`).click(); + } + + selectTestMethod(index = 0, method) { + cy.get(`#testMethod${index}`).select(method); + } + + selectPatient() { + cy.get( + "tbody > :nth-child(1) > :nth-child(1) > .cds--radio-button-wrapper > .cds--radio-button__label > .cds--radio-button__appearance", + ).click(); + } + + search() { + cy.get(":nth-child(1) > :nth-child(5) > .cds--btn").click(); + } + + searchByTest() { + cy.get(":nth-child(8) > #submit").click(); + } + + validatePatientResult(patient) { + cy.get("tbody > :nth-child(1) > :nth-child(2)").should( + "contain.text", + patient.lastName, + ); + cy.get("tbody > :nth-child(1) > :nth-child(3)").should( + "contain.text", + patient.firstName, + ); + } + + referSample(index = 0, reason, institute) { + cy.get(`#referralReason${index}`).select(reason); + cy.get(`#institute${index}`).select(institute); + } + + selectRefferedTest() { + cy.get( + "tbody > tr > .cds--table-column-checkbox > .cds--checkbox--inline > .cds--checkbox-label", + ).click(); + } + + selectAnalysisStatus(status) { + cy.get("#analysisStatus").select(status); + } + selectTestName(testName) { + cy.get("#testName").select(testName); + } + + printReport() { + cy.get(":nth-child(6) > :nth-child(2) > .cds--btn") + .should("be.visible") + .click(); + } + + setResultValue(index = 0, value) { + cy.get(`#resultValue${index}`).select(value); + } + + submitResults() { + cy.get("#submit").click(); + } +} + +export default Result; diff --git a/frontend/cypress/pages/RoutineReportPage.js b/frontend/cypress/pages/RoutineReportPage.js new file mode 100644 index 0000000000..590843ac7d --- /dev/null +++ b/frontend/cypress/pages/RoutineReportPage.js @@ -0,0 +1,74 @@ +class RoutineReportPage { + navigateToSection(sectionNumber, subsectionNumber) { + cy.get( + `.cds--white > :nth-child(1) > .cds--side-nav__navigation > .cds--side-nav__items > :nth-child(${sectionNumber}) > .cds--side-nav__item > .cds--side-nav__submenu`, + ).click(); + cy.get( + `:nth-child(${sectionNumber}) > .cds--side-nav__item > .cds--side-nav__menu > :nth-child(${subsectionNumber}) > .cds--side-nav__menu-item > .cds--side-nav__link`, + ).click(); + } + + validatePageHeader(expectedText) { + cy.get("section > h3, h1").should("have.text", expectedText); + } + + validateFieldVisibility(selector) { + cy.get(selector).should("be.visible"); + } + + validateButtonDisabled(selector) { + cy.get(selector).should("be.disabled"); + } + + validateButtonVisible(selector) { + cy.get(selector).should("be.visible"); + } + + visitRoutineReports() { + cy.get(":nth-child(2) > .cds--link").click(); + } + + toggleAccordion(accordionNumber) { + cy.get( + `:nth-child(${accordionNumber})> .cds--accordion__item > .cds--accordion__heading`, + ).click(); + } + + toggleAccordionPatient(accordionNumber) { + cy.get( + `:nth-child(${accordionNumber}) >.cds--accordion > .cds--accordion__item > .cds--accordion__heading`, + ).click(); + } + + toggleCheckbox(checkboxNumber, containerSelector) { + cy.get( + `${containerSelector} > :nth-child(${checkboxNumber}) input[type="checkbox"]`, + ).click({ force: true }); + } + + checkAllCheckboxes(start, end, containerSelector) { + for (let i = start; i <= end; i++) { + this.toggleCheckbox(i, containerSelector); + } + } + + validateAllCheckBox(check) { + cy.get( + ":nth-child(1) > .cds--sm\\:col-span-4 > :nth-child(2) > :nth-child(1) > .cds--checkbox-label", + ).should(check); + } + + uncheckCheckbox(checkboxNumber, containerSelector) { + this.toggleCheckbox(checkboxNumber, containerSelector); + } + + selectDropdown(selector, value) { + cy.get(selector).select(value, { force: true }); + } + + typeInDatePicker(selector, date) { + cy.get(selector).type(date); + } +} + +export default RoutineReportPage; diff --git a/frontend/cypress/pages/StudyReportPage.js b/frontend/cypress/pages/StudyReportPage.js new file mode 100644 index 0000000000..67aa496c50 --- /dev/null +++ b/frontend/cypress/pages/StudyReportPage.js @@ -0,0 +1,341 @@ +class StudyReportPage { + visitHomePage() { + homePage = loginPage.goToHomePage(); + } + + visitStudyReports() { + report = homePage.goToStudyReports(); + } + + clickSideNavMenuItem(nthChild, submenuChild) { + cy.get( + `.cds--side-nav__items > :nth-child(${nthChild}) > .cds--side-nav__item > .cds--side-nav__submenu`, + ).click(); + cy.get( + `:nth-child(${nthChild}) > .cds--side-nav__item > .cds--side-nav__menu > :nth-child(${submenuChild}) > .cds--side-nav__menu-item > .cds--side-nav__link`, + ).click(); + } + + verifyButtonDisabled() { + cy.get("section > .cds--btn").should("be.disabled"); + } + + typeInField(fieldId, value) { + cy.get(`#${fieldId}`).type(value, { force: true }); + } + + verifyButtonVisible() { + cy.get("section > .cds--btn").should("be.visible"); + } + + // verifyHeaderText(expectedText) { + // cy.get('.cds--sm\\:col-span-4 > section > h3').should('have.text', expectedText); + // } + + verifyHeaderText(selector, expectedText) { + cy.get(selector).should("have.text", expectedText); + } + + typeInDate(fieldId, value) { + cy.get(`#${fieldId}`).type(value); + } + + clickAccordionItem(nthChild) { + cy.get( + `:nth-child(${nthChild}) >.cds--accordion__item > .cds--accordion__heading`, + ).click(); + } + + clickAccordionPatient(nthChild) { + cy.get( + `:nth-child(${nthChild}) >.cds--accordion > .cds--accordion__item > .cds--accordion__heading`, + ).click(); + } + + verifyElementVisible(selector) { + cy.get(selector).should("be.visible"); + } + + selectDropdown(optionId, value) { + cy.get(`#${optionId}`).select(value); + } + + visitStudyReports() { + cy.get(":nth-child(2) > .cds--link").click({ force: true }); + } + + visitARVInitialVersion1() { + this.clickSideNavMenuItem(1, 1); + this.verifyButtonDisabled(); + this.typeInField("from", "DEV0124000000000000"); + this.verifyButtonVisible(); + } + + visitARVInitialVersion2() { + this.visitStudyReports(); + this.clickSideNavMenuItem(1, 2); + this.verifyHeaderText( + ".cds--sm\\:col-span-4 > section > h3", + "ARV-initial", + ); + this.verifyButtonDisabled(); + this.typeInField("from", "DEV0124000000000000"); + this.verifyButtonVisible(); + } + + visitARVFollowUpVersion1() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(1, 3); + this.verifyHeaderText( + ".cds--sm\\:col-span-4 > section > h3", + "ARV-Follow-up", + ); + this.verifyButtonDisabled(); + this.typeInField("from", "DEV0124000000000000"); + this.verifyButtonVisible(); + } + + visitARVFollowUpVersion2() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(1, 4); + this.verifyHeaderText( + ".cds--sm\\:col-span-4 > section > h3", + "ARV-Follow-up", + ); + this.verifyButtonDisabled(); + this.typeInField("from", "DEV0124000000000000"); + this.verifyButtonVisible(); + } + + visitARVFollowUpVersion3() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(1, 5); + this.verifyHeaderText( + ".cds--sm\\:col-span-4 > section > h3", + "ARV -->Initial-FollowUp-VL", + ); + this.verifyButtonDisabled(); + this.typeInField("from", "DEV0124000000000000"); + this.verifyButtonVisible(); + } + + visitAuditTrailReport() { + cy.get( + ":nth-child(11) > .cds--side-nav__item > .cds--side-nav__submenu", + ).click(); + cy.get( + ":nth-child(11) > .cds--side-nav__item > .cds--side-nav__menu > div > .cds--side-nav__menu-item > .cds--side-nav__link", + ).click(); + } + + validateAudit() { + cy.get("section > .cds--btn").click(); + cy.get(":nth-child(8) > :nth-child(2)").should( + "have.text", + "Optimus Prime", + ); + } + + visitEIDVersion1() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(2, 1); + this.verifyHeaderText( + ":nth-child(1) > .cds--sm\\:col-span-4 > :nth-child(1) > section > h3", + "Diagnostic for children with DBS-PCR", + ); + this.clickAccordionPatient(2); + this.verifyElementVisible("#patientId"); + this.verifyElementVisible("#local_search"); + this.clickAccordionPatient(2); + this.clickAccordionItem(3); + this.verifyElementVisible("#from"); + this.verifyElementVisible("#to"); + this.clickAccordionItem(3); + this.clickAccordionItem(6); + this.verifyElementVisible("#siteName"); + this.clickAccordionItem(6); + cy.get(":nth-child(7) > :nth-child(2) > .cds--btn").should("be.visible"); + } + + visitEIDVersion2() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(2, 2); + this.verifyHeaderText( + ".cds--sm\\:col-span-4 > section > h3", + "Diagnostic for children with DBS-PCR", + ); + this.verifyButtonDisabled(); + this.typeInField("from", "DEV0124000000000000"); + this.verifyButtonVisible(); + } + + visitVLVersion() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(3, 1); + this.verifyHeaderText( + ":nth-child(1) > .cds--sm\\:col-span-4 > :nth-child(1) > section > h3", + "Viral Load", + ); + this.clickAccordionPatient(2); + this.verifyElementVisible("#patientId"); + this.verifyElementVisible("#local_search"); + this.clickAccordionPatient(2); + this.clickAccordionItem(3); + this.verifyElementVisible("#from"); + this.verifyElementVisible("#to"); + this.clickAccordionItem(3); + this.clickAccordionItem(6); + this.verifyElementVisible("#siteName"); + this.clickAccordionItem(6); + cy.get(":nth-child(7) > :nth-child(2) > .cds--btn").should("be.visible"); + } + + visitIntermediateVersion1() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(4, 1); + this.verifyHeaderText( + ".cds--sm\\:col-span-4 > section > h3", + "Indeterminate", + ); + this.verifyButtonDisabled(); + this.typeInField("from", "DEV0124000000000000"); + this.verifyButtonVisible(); + } + + visitIntermediateVersion2() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(4, 2); + this.verifyHeaderText( + ".cds--sm\\:col-span-4 > section > h3", + "Indeterminate", + ); + this.verifyButtonDisabled(); + this.typeInField("from", "DEV0124000000000000"); + this.verifyButtonVisible(); + } + + visitIntermediateByService() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(4, 3); + this.verifyHeaderText( + ".cds--lg\\:col-span-16 > section > h3", + "Indeterminate", + ); + this.typeInDate("startDate", "01/02/2023"); + this.typeInField("siteName", "CAME", { force: true }); + this.verifyElementVisible("#siteName"); + } + + visitSpecialRequest() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(5, 1); + this.verifyHeaderText( + ".cds--sm\\:col-span-4 > section > h3", + "Special Request", + ); + this.verifyButtonDisabled(); + this.typeInField("from", "DEV0124000000000000"); + this.verifyButtonVisible(); + } + + visitCollectedARVPatientReport() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(6, 1); + this.verifyHeaderText( + ":nth-child(1) > .cds--sm\\:col-span-4 > :nth-child(1) > section > h3", + "Collected ARV Patient Report", + ); + this.verifyButtonDisabled(); + this.typeInField("nationalID", "UG-23SLHD7DBD"); + this.verifyButtonVisible(); + } + + visitAssociatedPatientReport() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(7, 1); + this.verifyHeaderText( + ":nth-child(1) > .cds--sm\\:col-span-4 > :nth-child(1) > section > h3", + "Associated Patient Report", + ); + this.verifyButtonDisabled(); + this.typeInField("nationalID", "UG-23SLHD7DBD"); + this.verifyButtonVisible(); + } + + visitNonConformityReportByDate() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(9, 1); + this.verifyHeaderText("h1", "Non-conformity Report By Date"); + this.verifyButtonDisabled(); + this.typeInDate("startDate", "01/02/2023"); + this.verifyButtonVisible(); + } + + visitNonConformityReportByUnitAndReason() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(9, 2); + this.verifyHeaderText("h1", "Non Conformity Report by Unit and Reason"); + this.verifyButtonDisabled(); + this.typeInDate("startDate", "01/02/2023"); + this.verifyButtonVisible(); + } + + visitNonConformityReportByLabNo() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(9, 3); + this.verifyHeaderText( + ".cds--sm\\:col-span-4 > section > h3", + "ARV -->Initial-FollowUp-VL", + ); + this.verifyButtonDisabled(); + this.typeInField("from", "DEV0124000000000000"); + this.verifyButtonVisible(); + } + + visitNonConformityReportByNotification() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(9, 4); + this.verifyHeaderText( + ".cds--sm\\:col-span-4 > section > h3", + "Non-conformity notification", + ); + this.verifyButtonVisible(); + } + + visitNonConformityReportFollowUpRequired() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(9, 5); + this.verifyHeaderText("h1", "Follow-up Required"); + this.verifyButtonDisabled(); + this.typeInDate("startDate", "01/02/2023"); + this.verifyButtonVisible(); + } + + visitGeneralReportInExportByDate() { + this.visitStudyReports(); + + this.clickSideNavMenuItem(10, 1); + this.verifyHeaderText("h1", "Export a CSV File by Date"); + this.selectDropdown("studyType", "Testing"); + this.selectDropdown("dateType", "Order Date"); + } +} + +export default StudyReportPage; diff --git a/frontend/cypress/pages/Validation.js b/frontend/cypress/pages/Validation.js new file mode 100644 index 0000000000..d6ed96eb82 --- /dev/null +++ b/frontend/cypress/pages/Validation.js @@ -0,0 +1,27 @@ +class Validation { + checkForHeading() { + cy.get("section > h3").should("contain.text", "Validation"); + } + + selectTestUnit(unitType) { + cy.get("#unitType").select(unitType); + } + + validateTestUnit(unitType) { + cy.get("#cell-testName-0 > .sampleInfo").should("contain.text", unitType); + } + + enterLabNumberAndSearch(labNo) { + cy.get("#accessionNumber").type(labNo); + cy.get(".cds--sm\\:col-span-4.cds--lg\\:col-span-16 > #submit").click(); + cy.get("#cell-sampleInfo-0 > .sampleInfo").should("contain.text", labNo); + } + + saveResults(note) { + cy.get("#cell-save-0 > .cds--form-item > .cds--checkbox-label").click(); + cy.get("#resultList0\\.note").type(note); + cy.get(":nth-child(3) > #submit").click(); + } +} + +export default Validation; diff --git a/frontend/src/App.js b/frontend/src/App.js index eff531cd88..fb4752152b 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,10 +1,11 @@ import React, { useState, useEffect } from "react"; import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; -import { confirmAlert } from "react-confirm-alert"; import { IntlProvider } from "react-intl"; +import { confirmAlert } from "react-confirm-alert"; import Layout from "./components/layout/Layout"; import Home from "./components/Home"; import Login from "./components/Login"; +import LandingPage from "./components/home/LandingPage"; import { Admin } from "./components"; import ResultSearch from "./components/resultPage/ResultSearch"; import UserSessionDetailsContext from "./UserSessionDetailsContext"; @@ -209,6 +210,11 @@ export default function App() { } /> + } + /> { - firstInput.current.focus(); + firstInput?.current?.focus(); const interval = setInterval(() => { checkLogin(); @@ -129,6 +130,26 @@ function Login(props) { }); }; + const renderOauthButtons = () => { + return ( + + {configurationProperties?.oauthUrls?.map((url) => ( + + ))} + + ); + }; + return ( <>
@@ -167,45 +188,50 @@ function Login(props) { - - - + {configurationProperties?.useFormLogin == "true" && ( + <> + + + + + )} {configurationProperties?.useSaml == "true" && ( )} + {configurationProperties?.useOauth == "true" && + renderOauthButtons()} )} diff --git a/frontend/src/components/admin/Admin.js b/frontend/src/components/admin/Admin.js index 179efad4fc..4738e7abcc 100644 --- a/frontend/src/components/admin/Admin.js +++ b/frontend/src/components/admin/Admin.js @@ -29,6 +29,7 @@ import { Bullhorn, User, BatchJob, + Popup, } from "@carbon/icons-react"; import PathRoute from "../utils/PathRoute"; import CalculatedValue from "./calculatedValue/CalculatedValueForm"; @@ -40,7 +41,7 @@ import { SideNavMenuItem, } from "@carbon/react"; import { CommonProperties } from "./menu/CommonProperties"; -import ConfigMenuDisplay from "./formEntry/common/ConfigMenuDisplay"; +import ConfigMenuDisplay from "./generalConfig/common/ConfigMenuDisplay"; import ProviderMenu from "./ProviderMenu/ProviderMenu"; import BarcodeConfiguration from "./barcodeConfiguration/BarcodeConfiguration"; import AnalyzerTestName from "./analyzerTestName/AnalyzerTestName.js"; @@ -54,6 +55,8 @@ import UserManagement from "./userManagement/UserManagement"; import UserAddModify from "./userManagement/UserAddModify"; import ManageMethod from "./testManagement/ManageMethod.js"; import BatchTestReassignmentAndCancelation from "./BatchTestReassignmentAndCancellation/BatchTestReassignmentAndCancelation.js"; +import TestNotificationConfigMenu from "./testNotificationConfigMenu/TestNotificationConfigMenu.js"; +import TestNotificationConfigEdit from "./testNotificationConfigMenu/TestNotificationConfigEdit.js"; function Admin() { const intl = useIntl(); @@ -188,6 +191,9 @@ function Admin() { defaultMessage={"Common Properties"} /> + + + @@ -325,6 +331,12 @@ function Admin() { id="sidenav.label.admin.formEntry.PrintedReportsconfig" /> + + + + + + diff --git a/frontend/src/components/admin/formEntry/common/ConfigMenuDisplay.js b/frontend/src/components/admin/generalConfig/common/ConfigMenuDisplay.js similarity index 99% rename from frontend/src/components/admin/formEntry/common/ConfigMenuDisplay.js rename to frontend/src/components/admin/generalConfig/common/ConfigMenuDisplay.js index 53228ec4d9..2d4eca72a6 100644 --- a/frontend/src/components/admin/formEntry/common/ConfigMenuDisplay.js +++ b/frontend/src/components/admin/generalConfig/common/ConfigMenuDisplay.js @@ -33,7 +33,7 @@ import { import config from "../../../../config.json"; import { FormattedMessage, useIntl } from "react-intl"; import PageBreadCrumb from "../../../common/PageBreadCrumb.js"; -import GenericConfigEdit from "../../formEntry/common/GenericConfigEdit.js"; +import GenericConfigEdit from "../../generalConfig/common/GenericConfigEdit.js"; let breadcrumbs = [{ label: "home.label", link: "/" }]; function ConfigMenuDisplay(props) { diff --git a/frontend/src/components/admin/formEntry/common/GenericConfigEdit.js b/frontend/src/components/admin/generalConfig/common/GenericConfigEdit.js similarity index 97% rename from frontend/src/components/admin/formEntry/common/GenericConfigEdit.js rename to frontend/src/components/admin/generalConfig/common/GenericConfigEdit.js index 379a934a95..179139bd50 100644 --- a/frontend/src/components/admin/formEntry/common/GenericConfigEdit.js +++ b/frontend/src/components/admin/generalConfig/common/GenericConfigEdit.js @@ -98,7 +98,8 @@ const GenericConfigEdit = ({ menuType, ID }) => { setTextInputEnglishValue(newValue); updateFormEntryConfig({ localization: { - ...FormEntryConfig.localization, + id: FormEntryConfig.localization.id, + description: FormEntryConfig.localization.description, localeValues: { ...FormEntryConfig.localization.localeValues, en: newValue, @@ -112,7 +113,8 @@ const GenericConfigEdit = ({ menuType, ID }) => { setTextInputFrenchValue(newValue); updateFormEntryConfig({ localization: { - ...FormEntryConfig.localization, + id: FormEntryConfig.localization.id, + description: FormEntryConfig.localization.description, localeValues: { ...FormEntryConfig.localization.localeValues, fr: newValue, @@ -332,7 +334,7 @@ const GenericConfigEdit = ({ menuType, ID }) => { {!FormEntryConfig.tag && ( - + { <>
- + } @@ -353,7 +355,7 @@ const GenericConfigEdit = ({ menuType, ID }) => { onChange={handleInputEnglishChange} /> - + } diff --git a/frontend/src/components/admin/testNotificationConfigMenu/TestNotificationConfigEdit.js b/frontend/src/components/admin/testNotificationConfigMenu/TestNotificationConfigEdit.js new file mode 100644 index 0000000000..f61a05a659 --- /dev/null +++ b/frontend/src/components/admin/testNotificationConfigMenu/TestNotificationConfigEdit.js @@ -0,0 +1,803 @@ +import React, { useContext, useState, useEffect, useRef } from "react"; +import { + Heading, + Button, + Loading, + Grid, + Column, + Section, + DataTable, + Table, + TableHead, + TableRow, + TableBody, + TableHeader, + TableCell, + TableSelectRow, + TableSelectAll, + TableContainer, + Pagination, + Search, + Modal, + TextInput, + Dropdown, + TextArea, + Checkbox, +} from "@carbon/react"; +import { + getFromOpenElisServer, + postToOpenElisServerFullResponse, + postToOpenElisServerJsonResponse, +} from "../../utils/Utils.js"; +import { + ConfigurationContext, + NotificationContext, +} from "../../layout/Layout.js"; +import { + AlertDialog, + NotificationKinds, +} from "../../common/CustomNotification.js"; +import { FormattedMessage, injectIntl, useIntl } from "react-intl"; +import PageBreadCrumb from "../../common/PageBreadCrumb.js"; +import { ArrowLeft, ArrowRight, Cost } from "@carbon/icons-react"; +import ActionPaginationButtonType from "../../common/ActionPaginationButtonType.js"; + +let breadcrumbs = [ + { label: "home.label", link: "/" }, + { label: "breadcrums.admin.managment", link: "/MasterListsPage" }, + { + label: "testnotificationconfig.browse.title", + link: "/MasterListsPage#testNotificationConfigMenu", + }, +]; + +function TestNotificationConfigEdit() { + const { notificationVisible, setNotificationVisible, addNotification } = + useContext(NotificationContext); + + const intl = useIntl(); + + const ID = (() => { + const hash = window.location.hash; + if (hash.includes("?")) { + const queryParams = hash.split("?")[1]; + const urlParams = new URLSearchParams(queryParams); + return urlParams.get("testId"); + } + return "0"; + })(); + + const componentMounted = useRef(false); + const [indMsg, setIndMsg] = useState("0"); + const [loading, setLoading] = useState(true); + const [saveButton, setSaveButton] = useState(false); + const [sysDefaultMsg, setSysDefaultMsg] = useState(true); + const [testNotificationConfigEditData, setTestNotificationConfigEditData] = + useState({}); + const [ + testNotificationConfigEditDataPost, + setTestNotificationConfigEditDataPost, + ] = useState({}); + const [testNamesList, setTestNamesList] = useState([]); + const [testName, setTestName] = useState(""); + const [testNotificationConfigMenuList, setTestNotificationConfigMenuList] = + useState([]); + + useEffect(() => { + if (testNotificationConfigEditData) { + setTestNotificationConfigEditDataPost( + (prevSetTestNotificationConfigDataPost) => ({ + ...prevSetTestNotificationConfigDataPost, + formName: testNotificationConfigEditData.formName, + formMethod: testNotificationConfigEditData.formMethod, + cancelAction: testNotificationConfigEditData.cancelAction, + submitOnCancel: testNotificationConfigEditData.submitOnCancel, + cancelMethod: testNotificationConfigEditData.cancelMethod, + config: testNotificationConfigEditData.config, + systemDefaultPayloadTemplate: + testNotificationConfigEditData.systemDefaultPayloadTemplate, + editSystemDefaultPayloadTemplate: + testNotificationConfigEditData.editSystemDefaultPayloadTemplate, + }), + ); + } + }, [testNotificationConfigEditData]); + + const handleMenuItems = (res) => { + if (res) { + setTestNotificationConfigEditData(res); + } + setLoading(false); + }; + + const handleTestNamesList = (res) => { + if (res) { + setTestNamesList(res); + } + setLoading(false); + }; + + useEffect(() => { + componentMounted.current = true; + getFromOpenElisServer( + `/rest/TestNotificationConfig?testId=${ID}`, + handleMenuItems, + ); + getFromOpenElisServer(`/rest/test-list`, handleTestNamesList); + return () => { + componentMounted.current = false; + }; + }, [ID]); + + useEffect(() => { + const testId = testNotificationConfigEditData?.config?.testId; + if (testNamesList && testId) { + const test = testNamesList.find((item) => item.id === testId); + if (test) { + setTestName(test.value); + } + } + }, [testNamesList, testNotificationConfigEditData]); + + function handleSubjectTemplateChange(e) { + setTestNotificationConfigEditDataPost((prev) => ({ + ...prev, + editSystemDefaultPayloadTemplate: true, + })); + setTestNotificationConfigEditDataPost((prev) => ({ + ...prev, + systemDefaultPayloadTemplate: { + ...prev.systemDefaultPayloadTemplate, + subjectTemplate: e.target.value, + }, + })); + } + + function handleMessageTemplateChange(e) { + setTestNotificationConfigEditDataPost((prev) => ({ + ...prev, + editSystemDefaultPayloadTemplate: true, + })); + setTestNotificationConfigEditDataPost((prev) => ({ + ...prev, + systemDefaultPayloadTemplate: { + ...prev.systemDefaultPayloadTemplate, + messageTemplate: e.target.value, + }, + })); + } + + const handleCheckboxChange = (e) => { + const { id, checked } = e.target; + + setTestNotificationConfigEditDataPost((prev) => { + const updatedConfig = { ...prev.config }; + + switch (id) { + case "providerEmail": + updatedConfig.providerEmail.active = checked; + break; + case "patientEmail": + updatedConfig.patientEmail.active = checked; + break; + case "patientSMS": + updatedConfig.patientSMS.active = checked; + break; + case "providerSMS": + updatedConfig.providerSMS.active = checked; + break; + default: + break; + } + + return { + ...prev, + config: updatedConfig, + }; + }); + }; + + function testNotificationConfigEditSavePostCall() { + setLoading(true); + postToOpenElisServerJsonResponse( + `/rest/TestNotificationConfig`, + JSON.stringify(testNotificationConfigEditDataPost), + (res) => { + testNotificationConfigEditSavePostCallBack(res); + }, + ); + } + + function testNotificationConfigEditSavePostCallBack(res) { + if (res) { + addNotification({ + title: intl.formatMessage({ + id: "notification.title", + }), + message: intl.formatMessage({ + id: "notification.user.post.save.success", + }), + kind: NotificationKinds.success, + }); + setNotificationVisible(true); + } else { + addNotification({ + kind: NotificationKinds.error, + title: intl.formatMessage({ id: "notification.title" }), + message: intl.formatMessage({ id: "server.error.msg" }), + }); + setNotificationVisible(true); + } + setLoading(false); + } + + return ( + <> + {notificationVisible === true ? : ""} + {loading && } +
+ + + +
+
+ + + +
+
+
+
+
+ + +
+
+ + {testName && } + +
+
+
+
+
+
+ {testNotificationConfigEditDataPost?.config && ( + + + + } + checked={ + testNotificationConfigEditDataPost.config.patientEmail + ?.active ?? false + } + onChange={handleCheckboxChange} + /> + + + + } + checked={ + testNotificationConfigEditDataPost.config.patientSMS + ?.active ?? false + } + onChange={handleCheckboxChange} + /> + + + + } + checked={ + testNotificationConfigEditDataPost.config.providerSMS + ?.active ?? false + } + onChange={handleCheckboxChange} + /> + + + + } + checked={ + testNotificationConfigEditDataPost.config.providerEmail + ?.active ?? false + } + onChange={handleCheckboxChange} + /> + + + )} +
+
+
+ + +
+
+ + + +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ + + +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+ + +
+
+
+ + + +
+
+
+
+ + + +
+
+ + + + + + handleSubjectTemplateChange(e)} + /> + + +
+ + + + + +
+ + +