From a725fd5be49e2959eb1c3642293f2569ef83e56c Mon Sep 17 00:00:00 2001 From: Piumal Rathnayake Date: Sun, 9 Apr 2023 16:17:42 +0530 Subject: [PATCH 001/660] O3-1937: Write E2E test for Patient List (#578) * O3-1937: Write E2E test for Patient List * Add updated urls * Remove cohort member before deleting the patient * Comment the delete test * Provide cohort type when editing * Update the e2e tests according to the new changes * Update the edit list test * Fix the searchbox locator * Fix the failing tests * Update selectors --------- Co-authored-by: Anjula Shanaka --- e2e/commands/cohortOperations.ts | 84 +++++++++++++++++ e2e/commands/index.ts | 1 + e2e/pages/index.ts | 1 + e2e/pages/patientListsPage.ts | 38 ++++++++ e2e/specs/patientList.spec.ts | 92 +++++++++++++++++++ .../create-edit-list.component.tsx | 1 + .../patient-list-detail.component.tsx | 4 +- .../patient-list-table.component.tsx | 2 +- .../patient-table/patient-table.component.tsx | 2 +- 9 files changed, 221 insertions(+), 4 deletions(-) create mode 100644 e2e/commands/cohortOperations.ts create mode 100644 e2e/pages/patientListsPage.ts create mode 100644 e2e/specs/patientList.spec.ts diff --git a/e2e/commands/cohortOperations.ts b/e2e/commands/cohortOperations.ts new file mode 100644 index 000000000..2c55f0269 --- /dev/null +++ b/e2e/commands/cohortOperations.ts @@ -0,0 +1,84 @@ +import { APIRequestContext, expect } from '@playwright/test'; +import { Patient } from './patientOperations'; + +export interface CohortType { + uuid: string; + name: string; + description: string; + display: string; + links: { rel: string; uri: string; resourceAlias: string }[]; + resourceVersion: string; +} + +export interface Cohort { + uuid: string; + name: string; + description: string; + attributes: any[]; + links: any[]; + location: any; + groupCohort: boolean | null; + startDate: Date; + endDate: Date; + voidReason: string | null; + voided: boolean; + isStarred?: boolean; + type?: string; + size: number; + cohortType?: CohortType; + resourceVersion: string; +} + +export interface CohortMember { + attributes: Array; + description: string; + endDate: string; + startDate: string; + name: string; + uuid: string; + patient: Patient; +} + +export const generateRandomCohort = async (api: APIRequestContext): Promise => { + const cohortRes = await api.post('cohortm/cohort', { + data: { + name: `Cohort ${Math.floor(Math.random() * 10000)}`, + description: `Cohort description ${Math.floor(Math.random() * 10000)}`, + cohortType: 'e71857cb-33af-4f2c-86ab-7223bcfa37ad', + groupCohort: false, + startDate: new Date().toISOString(), + }, + }); + await expect(cohortRes.ok()).toBeTruthy(); + return await cohortRes.json(); +}; + +export const deleteCohort = async (api: APIRequestContext, uuid: string) => { + await api.delete(`cohortm/cohort/${uuid}`, { + data: { + voidReason: 'Test void reason', + }, + }); +}; + +export const addPatientToCohort = async ( + api: APIRequestContext, + cohortUuid: string, + patientUuid: string, +): Promise => { + const cohortMemberRes = await api.post(`cohortm/cohortmember`, { + data: { + patient: patientUuid, + cohort: cohortUuid, + startDate: new Date().toISOString(), + }, + }); + await expect(cohortMemberRes.ok()).toBeTruthy(); + return await cohortMemberRes.json(); +}; + +export const removePatientFromCohort = async (api: APIRequestContext, cohortMemberUuid: string) => { + await api.delete(`cohortm/cohortmember/${cohortMemberUuid}`, { + data: {}, + }); +}; diff --git a/e2e/commands/index.ts b/e2e/commands/index.ts index da541a155..cab5a29ba 100644 --- a/e2e/commands/index.ts +++ b/e2e/commands/index.ts @@ -2,3 +2,4 @@ export * from './patientOperations'; export * from './encounterOperations'; export * from './visitOperations'; export * from './providerOperations'; +export * from './cohortOperations'; diff --git a/e2e/pages/index.ts b/e2e/pages/index.ts index fb80fbcf7..65d72dd22 100644 --- a/e2e/pages/index.ts +++ b/e2e/pages/index.ts @@ -1,2 +1,3 @@ export * from './homePage'; export * from './registrationAndEditPage'; +export * from './patientListsPage'; diff --git a/e2e/pages/patientListsPage.ts b/e2e/pages/patientListsPage.ts new file mode 100644 index 000000000..0bdc3d059 --- /dev/null +++ b/e2e/pages/patientListsPage.ts @@ -0,0 +1,38 @@ +import { Page } from '@playwright/test'; + +export class PatientListsPage { + constructor(readonly page: Page) {} + + readonly allListsButton = () => this.page.getByRole('tab', { name: 'All lists' }); + readonly patientListsTable = () => this.page.getByTestId('patientListsTable'); + readonly patientListHeader = () => this.page.getByTestId('patientListHeader'); + readonly patientsTable = () => this.page.getByTestId('patientsTable'); + + async goto(patientListUuid?: string) { + await this.page.goto(`home/patient-lists/${patientListUuid ?? ''}`); + } + + async addNewPatientList(listName: string, description: string) { + await this.page.getByRole('button', { name: 'New List' }).click(); + await this.page.getByLabel('List name').fill(listName); + await this.page.getByLabel('Describe the purpose of this list in a few words').fill(description); + await this.page.getByRole('button', { name: 'Create list' }).click(); + } + + async editPatientList(listName: string, description: string) { + await this.page.getByRole('button', { name: 'Actions' }).click(); + await this.page.getByRole('menuitem', { name: 'Edit Name/ Description' }).click(); + await this.page.getByLabel('List name').fill(listName); + await this.page.getByLabel('Describe the purpose of this list in a few words').fill(description); + await this.page.getByRole('button', { name: 'Edit list' }).click(); + } + + async searchPatientList(listName: string) { + await this.page.getByRole('searchbox').fill(listName); + } + + async deletePatientList() { + await this.page.getByRole('button', { name: 'Actions' }).click(); + await this.page.getByRole('menuitem', { name: 'Delete' }).click(); + } +} diff --git a/e2e/specs/patientList.spec.ts b/e2e/specs/patientList.spec.ts new file mode 100644 index 000000000..f079b5763 --- /dev/null +++ b/e2e/specs/patientList.spec.ts @@ -0,0 +1,92 @@ +import { test } from '../core'; +import { PatientListsPage } from '../pages'; +import { expect } from '@playwright/test'; +import { + addPatientToCohort, + Cohort, + CohortMember, + deleteCohort, + deletePatient, + generateRandomCohort, + generateRandomPatient, + Patient, + removePatientFromCohort, +} from '../commands'; + +let patient: Patient; +let cohort: Cohort; +let createdCohortUuid: string; +let createdCohortMember: CohortMember; + +test.beforeEach(async ({ api }) => { + patient = await generateRandomPatient(api); + cohort = await generateRandomCohort(api); +}); + +test('should be able to create and edit a patient list', async ({ page }) => { + const patientListPage = new PatientListsPage(page); + await patientListPage.goto(); + + // Create a new patient list + const patientListName = `Cohort ${Math.floor(Math.random() * 10000)}`; + const patientListDescription = `Cohort Description ${Math.floor(Math.random() * 10000)}`; + await patientListPage.addNewPatientList(patientListName, patientListDescription); + + await patientListPage.allListsButton().click(); + await patientListPage.searchPatientList(patientListName); + await patientListPage.patientListsTable().getByText(patientListName).click(); + + await expect(page).toHaveURL(new RegExp('^[\\w\\d:\\/.-]+\\/patient-lists\\/[\\w\\d-]+$')); + createdCohortUuid = /patient-lists\/([\w\d-]+)/.exec(page.url())?.[1] ?? null; + + await expect(patientListPage.patientListHeader()).toHaveText(new RegExp(patientListName)); + await expect(patientListPage.patientListHeader()).toHaveText(new RegExp(patientListDescription)); + await expect(patientListPage.patientListHeader()).toHaveText(/0 patients/); + + // Edit the patient list + const editedPatientListName = patientListName + ' edited'; + const editedPatientListDescription = patientListDescription + ' edited'; + await patientListPage.editPatientList(editedPatientListName, editedPatientListDescription); + + await expect(patientListPage.patientListHeader()).toHaveText(new RegExp(editedPatientListName)); + await expect(patientListPage.patientListHeader()).toHaveText(new RegExp(editedPatientListDescription)); +}); + +test('should be able to delete a patient list', async ({ page }) => { + const patientListPage = new PatientListsPage(page); + await patientListPage.goto(cohort.uuid); + + await patientListPage.deletePatientList(); + + await patientListPage.allListsButton().click(); + await patientListPage.searchPatientList(cohort.name); + await expect(patientListPage.page.getByText('There are no patient lists to display')).toBeVisible(); +}); + +test('should be able to manage patients in a patient list', async ({ page, api }) => { + const patientListPage = new PatientListsPage(page); + + // Add a patient to the patient list + createdCohortMember = await addPatientToCohort(api, cohort.uuid, patient.uuid); + await patientListPage.goto(cohort.uuid); + await expect(patientListPage.patientListHeader()).toHaveText(/1 patients/); + await expect(patientListPage.patientsTable()).toHaveText(new RegExp(patient.person.display)); + + // Remove a patient from the patient list + await removePatientFromCohort(api, createdCohortMember.uuid); + await patientListPage.goto(cohort.uuid); + await expect(patientListPage.patientListHeader()).toHaveText(/0 patients/); + await expect(patientListPage.patientsTable()).not.toHaveText(new RegExp(patient.person.display)); + createdCohortMember = null; +}); + +test.afterEach(async ({ api }) => { + if (createdCohortMember) { + await removePatientFromCohort(api, createdCohortMember.uuid); + } + if (createdCohortUuid) { + await deleteCohort(api, createdCohortUuid); + } + await deletePatient(api, patient.uuid); + await deleteCohort(api, cohort.uuid); +}); diff --git a/packages/esm-patient-list-app/src/create-edit-patient-list/create-edit-list.component.tsx b/packages/esm-patient-list-app/src/create-edit-patient-list/create-edit-list.component.tsx index 57cf38a9f..c49678574 100644 --- a/packages/esm-patient-list-app/src/create-edit-patient-list/create-edit-list.component.tsx +++ b/packages/esm-patient-list-app/src/create-edit-patient-list/create-edit-list.component.tsx @@ -141,6 +141,7 @@ const CreateEditPatientList: React.FC = ({