Skip to content

Commit a725fd5

Browse files
O3-1937: Write E2E test for Patient List (openmrs#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 <[email protected]>
1 parent fc7946e commit a725fd5

File tree

9 files changed

+221
-4
lines changed

9 files changed

+221
-4
lines changed

e2e/commands/cohortOperations.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { APIRequestContext, expect } from '@playwright/test';
2+
import { Patient } from './patientOperations';
3+
4+
export interface CohortType {
5+
uuid: string;
6+
name: string;
7+
description: string;
8+
display: string;
9+
links: { rel: string; uri: string; resourceAlias: string }[];
10+
resourceVersion: string;
11+
}
12+
13+
export interface Cohort {
14+
uuid: string;
15+
name: string;
16+
description: string;
17+
attributes: any[];
18+
links: any[];
19+
location: any;
20+
groupCohort: boolean | null;
21+
startDate: Date;
22+
endDate: Date;
23+
voidReason: string | null;
24+
voided: boolean;
25+
isStarred?: boolean;
26+
type?: string;
27+
size: number;
28+
cohortType?: CohortType;
29+
resourceVersion: string;
30+
}
31+
32+
export interface CohortMember {
33+
attributes: Array<any>;
34+
description: string;
35+
endDate: string;
36+
startDate: string;
37+
name: string;
38+
uuid: string;
39+
patient: Patient;
40+
}
41+
42+
export const generateRandomCohort = async (api: APIRequestContext): Promise<Cohort> => {
43+
const cohortRes = await api.post('cohortm/cohort', {
44+
data: {
45+
name: `Cohort ${Math.floor(Math.random() * 10000)}`,
46+
description: `Cohort description ${Math.floor(Math.random() * 10000)}`,
47+
cohortType: 'e71857cb-33af-4f2c-86ab-7223bcfa37ad',
48+
groupCohort: false,
49+
startDate: new Date().toISOString(),
50+
},
51+
});
52+
await expect(cohortRes.ok()).toBeTruthy();
53+
return await cohortRes.json();
54+
};
55+
56+
export const deleteCohort = async (api: APIRequestContext, uuid: string) => {
57+
await api.delete(`cohortm/cohort/${uuid}`, {
58+
data: {
59+
voidReason: 'Test void reason',
60+
},
61+
});
62+
};
63+
64+
export const addPatientToCohort = async (
65+
api: APIRequestContext,
66+
cohortUuid: string,
67+
patientUuid: string,
68+
): Promise<CohortMember> => {
69+
const cohortMemberRes = await api.post(`cohortm/cohortmember`, {
70+
data: {
71+
patient: patientUuid,
72+
cohort: cohortUuid,
73+
startDate: new Date().toISOString(),
74+
},
75+
});
76+
await expect(cohortMemberRes.ok()).toBeTruthy();
77+
return await cohortMemberRes.json();
78+
};
79+
80+
export const removePatientFromCohort = async (api: APIRequestContext, cohortMemberUuid: string) => {
81+
await api.delete(`cohortm/cohortmember/${cohortMemberUuid}`, {
82+
data: {},
83+
});
84+
};

e2e/commands/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from './patientOperations';
22
export * from './encounterOperations';
33
export * from './visitOperations';
44
export * from './providerOperations';
5+
export * from './cohortOperations';

e2e/pages/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './homePage';
22
export * from './registrationAndEditPage';
3+
export * from './patientListsPage';

e2e/pages/patientListsPage.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Page } from '@playwright/test';
2+
3+
export class PatientListsPage {
4+
constructor(readonly page: Page) {}
5+
6+
readonly allListsButton = () => this.page.getByRole('tab', { name: 'All lists' });
7+
readonly patientListsTable = () => this.page.getByTestId('patientListsTable');
8+
readonly patientListHeader = () => this.page.getByTestId('patientListHeader');
9+
readonly patientsTable = () => this.page.getByTestId('patientsTable');
10+
11+
async goto(patientListUuid?: string) {
12+
await this.page.goto(`home/patient-lists/${patientListUuid ?? ''}`);
13+
}
14+
15+
async addNewPatientList(listName: string, description: string) {
16+
await this.page.getByRole('button', { name: 'New List' }).click();
17+
await this.page.getByLabel('List name').fill(listName);
18+
await this.page.getByLabel('Describe the purpose of this list in a few words').fill(description);
19+
await this.page.getByRole('button', { name: 'Create list' }).click();
20+
}
21+
22+
async editPatientList(listName: string, description: string) {
23+
await this.page.getByRole('button', { name: 'Actions' }).click();
24+
await this.page.getByRole('menuitem', { name: 'Edit Name/ Description' }).click();
25+
await this.page.getByLabel('List name').fill(listName);
26+
await this.page.getByLabel('Describe the purpose of this list in a few words').fill(description);
27+
await this.page.getByRole('button', { name: 'Edit list' }).click();
28+
}
29+
30+
async searchPatientList(listName: string) {
31+
await this.page.getByRole('searchbox').fill(listName);
32+
}
33+
34+
async deletePatientList() {
35+
await this.page.getByRole('button', { name: 'Actions' }).click();
36+
await this.page.getByRole('menuitem', { name: 'Delete' }).click();
37+
}
38+
}

e2e/specs/patientList.spec.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { test } from '../core';
2+
import { PatientListsPage } from '../pages';
3+
import { expect } from '@playwright/test';
4+
import {
5+
addPatientToCohort,
6+
Cohort,
7+
CohortMember,
8+
deleteCohort,
9+
deletePatient,
10+
generateRandomCohort,
11+
generateRandomPatient,
12+
Patient,
13+
removePatientFromCohort,
14+
} from '../commands';
15+
16+
let patient: Patient;
17+
let cohort: Cohort;
18+
let createdCohortUuid: string;
19+
let createdCohortMember: CohortMember;
20+
21+
test.beforeEach(async ({ api }) => {
22+
patient = await generateRandomPatient(api);
23+
cohort = await generateRandomCohort(api);
24+
});
25+
26+
test('should be able to create and edit a patient list', async ({ page }) => {
27+
const patientListPage = new PatientListsPage(page);
28+
await patientListPage.goto();
29+
30+
// Create a new patient list
31+
const patientListName = `Cohort ${Math.floor(Math.random() * 10000)}`;
32+
const patientListDescription = `Cohort Description ${Math.floor(Math.random() * 10000)}`;
33+
await patientListPage.addNewPatientList(patientListName, patientListDescription);
34+
35+
await patientListPage.allListsButton().click();
36+
await patientListPage.searchPatientList(patientListName);
37+
await patientListPage.patientListsTable().getByText(patientListName).click();
38+
39+
await expect(page).toHaveURL(new RegExp('^[\\w\\d:\\/.-]+\\/patient-lists\\/[\\w\\d-]+$'));
40+
createdCohortUuid = /patient-lists\/([\w\d-]+)/.exec(page.url())?.[1] ?? null;
41+
42+
await expect(patientListPage.patientListHeader()).toHaveText(new RegExp(patientListName));
43+
await expect(patientListPage.patientListHeader()).toHaveText(new RegExp(patientListDescription));
44+
await expect(patientListPage.patientListHeader()).toHaveText(/0 patients/);
45+
46+
// Edit the patient list
47+
const editedPatientListName = patientListName + ' edited';
48+
const editedPatientListDescription = patientListDescription + ' edited';
49+
await patientListPage.editPatientList(editedPatientListName, editedPatientListDescription);
50+
51+
await expect(patientListPage.patientListHeader()).toHaveText(new RegExp(editedPatientListName));
52+
await expect(patientListPage.patientListHeader()).toHaveText(new RegExp(editedPatientListDescription));
53+
});
54+
55+
test('should be able to delete a patient list', async ({ page }) => {
56+
const patientListPage = new PatientListsPage(page);
57+
await patientListPage.goto(cohort.uuid);
58+
59+
await patientListPage.deletePatientList();
60+
61+
await patientListPage.allListsButton().click();
62+
await patientListPage.searchPatientList(cohort.name);
63+
await expect(patientListPage.page.getByText('There are no patient lists to display')).toBeVisible();
64+
});
65+
66+
test('should be able to manage patients in a patient list', async ({ page, api }) => {
67+
const patientListPage = new PatientListsPage(page);
68+
69+
// Add a patient to the patient list
70+
createdCohortMember = await addPatientToCohort(api, cohort.uuid, patient.uuid);
71+
await patientListPage.goto(cohort.uuid);
72+
await expect(patientListPage.patientListHeader()).toHaveText(/1 patients/);
73+
await expect(patientListPage.patientsTable()).toHaveText(new RegExp(patient.person.display));
74+
75+
// Remove a patient from the patient list
76+
await removePatientFromCohort(api, createdCohortMember.uuid);
77+
await patientListPage.goto(cohort.uuid);
78+
await expect(patientListPage.patientListHeader()).toHaveText(/0 patients/);
79+
await expect(patientListPage.patientsTable()).not.toHaveText(new RegExp(patient.person.display));
80+
createdCohortMember = null;
81+
});
82+
83+
test.afterEach(async ({ api }) => {
84+
if (createdCohortMember) {
85+
await removePatientFromCohort(api, createdCohortMember.uuid);
86+
}
87+
if (createdCohortUuid) {
88+
await deleteCohort(api, createdCohortUuid);
89+
}
90+
await deletePatient(api, patient.uuid);
91+
await deleteCohort(api, cohort.uuid);
92+
});

packages/esm-patient-list-app/src/create-edit-patient-list/create-edit-list.component.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ const CreateEditPatientList: React.FC<CreateEditPatientListProps> = ({
141141
<div className={styles.input}>
142142
<Layer level={isTablet ? 1 : 0}>
143143
<TextArea
144+
id="list_description"
144145
name="description"
145146
onChange={handleChange}
146147
placeholder={t(

packages/esm-patient-list-app/src/patient-list-detail/patient-list-detail.component.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ const PatientListDetailComponent = () => {
9191
kind: 'success',
9292
}),
9393
)
94-
.then(() => navigate({ to: `${window.spaBase}/patient-list/` }))
94+
.then(() => navigate({ to: `${window.spaBase}/home/patient-lists/` }))
9595
.catch(() =>
9696
showToast({
9797
title: t('error', 'Error'),
@@ -105,7 +105,7 @@ const PatientListDetailComponent = () => {
105105
<main className={`omrs-main-content ${styles.patientListDetailsPage}`}>
106106
<section>
107107
<ExtensionSlot extensionSlotName="breadcrumbs-slot" />
108-
<div className={styles.cohortHeader}>
108+
<div className={styles.cohortHeader} data-testid="patientListHeader">
109109
<div>
110110
{patientListDetails && (
111111
<>

packages/esm-patient-list-app/src/patient-list-list/patient-list-table.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ const PatientListTable: React.FC<PatientListTableProps> = ({
8787
getTableContainerProps,
8888
}: DataTableCustomRenderProps) => (
8989
<TableContainer style={{ ...style, backgroundColor: 'transparent' }} {...getTableContainerProps()}>
90-
<Table {...getTableProps()} isSortable useZebraStyles>
90+
<Table {...getTableProps()} data-testid="patientListsTable" isSortable useZebraStyles>
9191
<TableHead>
9292
<TableRow>
9393
{headers.map((header) => (

packages/esm-patient-list-app/src/patient-table/patient-table.component.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ const PatientTable: React.FC<PatientTableProps> = ({
113113
<DataTable rows={rows} headers={columns} isSortable={true} useZebraStyles={true}>
114114
{({ rows, headers, getHeaderProps, getTableProps, getRowProps }) => (
115115
<TableContainer>
116-
<Table {...getTableProps()}>
116+
<Table {...getTableProps()} data-testid="patientsTable">
117117
<TableHead>
118118
<TableRow>
119119
{headers.map((header) => (

0 commit comments

Comments
 (0)