Skip to content

Commit

Permalink
(e2e) Test clinical forms workflow (#1504)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: Jayasanka <[email protected]>
  • Loading branch information
denniskigen and jayasanka-sack authored Nov 29, 2023
1 parent f1bb9d9 commit 0c20c49
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 6 deletions.
2 changes: 1 addition & 1 deletion e2e/pages/allergies-page.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Page } from '@playwright/test';
import { type Page } from '@playwright/test';

export class PatientAllergiesPage {
constructor(readonly page: Page) {}
Expand Down
11 changes: 11 additions & 0 deletions e2e/pages/chart-page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { type Page } from '@playwright/test';

export class ChartPage {
constructor(readonly page: Page) {}

readonly formsTable = () => this.page.getByRole('table', { name: /forms/i });

async goTo(patientUuid: string) {
await this.page.goto('/openmrs/spa/patient/' + patientUuid + '/chart');
}
}
2 changes: 1 addition & 1 deletion e2e/pages/conditions-page.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Page } from '@playwright/test';
import { type Page } from '@playwright/test';

export class ConditionsPage {
constructor(readonly page: Page) {}
Expand Down
2 changes: 2 additions & 0 deletions e2e/pages/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export * from './allergies-page';
export * from './chart-page';
export * from './conditions-page';
export * from './medications-page';
export * from './program-page';
export * from './vitals-and-biometrics-page';
export * from './visits-page';
2 changes: 1 addition & 1 deletion e2e/pages/medications-page.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Page } from '@playwright/test';
import { type Page } from '@playwright/test';

export class MedicationsPage {
constructor(readonly page: Page) {}
Expand Down
2 changes: 1 addition & 1 deletion e2e/pages/program-page.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Page } from '@playwright/test';
import { type Page } from '@playwright/test';

export class ProgramsPage {
constructor(readonly page: Page) {}
Expand Down
9 changes: 9 additions & 0 deletions e2e/pages/visits-page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { type Page } from '@playwright/test';

export class VisitsPage {
constructor(readonly page: Page) {}

async goTo(patientUuid: string) {
await this.page.goto(`patient/${patientUuid}/chart/Visits`);
}
}
2 changes: 1 addition & 1 deletion e2e/pages/vitals-and-biometrics-page.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Page } from '@playwright/test';
import { type Page } from '@playwright/test';

export class BiometricsAndVitalsPage {
constructor(readonly page: Page) {}
Expand Down
95 changes: 95 additions & 0 deletions e2e/specs/clinical-forms.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { expect } from '@playwright/test';
import { type Visit } from '@openmrs/esm-framework';
import { test } from '../core';
import { generateRandomPatient, deletePatient, type Patient, startVisit, endVisit } from '../commands';
import { ChartPage, VisitsPage } from '../pages';

let patient: Patient;
let visit: Visit;

const subjectiveFindings = `I've had a headache for the last two days`;
const objectiveFindings = `General appearance is healthy. No signs of distress. Head exam shows no abnormalities, no tenderness on palpation. Neurological exam is normal; cranial nerves intact, normal gait and coordination.`;
const assessment = `Diagnosis: Tension-type headache. Differential Diagnoses: Migraine, sinusitis, refractive error.`;
const plan = `Advise use of over-the-counter ibuprofen as needed for headache pain. Educate about proper posture during reading and screen time; discuss healthy sleep hygiene. Schedule a follow-up appointment in 2 weeks or sooner if the headache becomes more frequent or severe.`;

test.beforeEach(async ({ api }) => {
patient = await generateRandomPatient(api);
visit = await startVisit(api, patient.uuid);
});

test('Fill a clinical form', async ({ page, api }) => {
const chartPage = new ChartPage(page);
const visitsPage = new VisitsPage(page);

await test.step('When I visit the chart summary page', async () => {
await chartPage.goTo(patient.uuid);
});

await test.step('And I click the `Clinical forms` button on the siderail', async () => {
await chartPage.page.getByLabel(/clinical forms/i, { exact: true }).click();
});

await test.step('Then I should see the clinical forms workspace', async () => {
const headerRow = chartPage.formsTable().locator('thead > tr');

await expect(chartPage.page.getByPlaceholder(/search this list/i)).toBeVisible();
await expect(headerRow).toContainText(/form name \(a-z\)/i);
await expect(headerRow).toContainText(/last completed/i);

await expect(chartPage.page.getByRole('cell', { name: /ampath_poc_adult_return_visit_form/i })).toBeVisible();
await expect(chartPage.page.getByRole('cell', { name: /covid 19/i })).toBeVisible();
await expect(chartPage.page.getByRole('cell', { name: /laboratory test orders/i })).toBeVisible();
await expect(chartPage.page.getByRole('cell', { name: /laboratory test results/i })).toBeVisible();
await expect(chartPage.page.getByRole('cell', { name: /soap note template/i })).toBeVisible();
await expect(chartPage.page.getByRole('cell', { name: /surgical operation/i })).toBeVisible();
});

await test.step('And if I fill a form', async () => {
await chartPage.page.getByText(/soap note template/i).click();

await expect(chartPage.page.getByRole('button', { name: /save and close/i })).toBeVisible();
await expect(chartPage.page.getByRole('button', { name: /discard/i })).toBeVisible();

await chartPage.page.locator('#SOAPSubjectiveFindingsid').fill(subjectiveFindings);
await chartPage.page.locator('#SOAPObjectiveFindingsid').fill(objectiveFindings);
await chartPage.page.locator('#SOAPAssessmentid').fill(assessment);
await chartPage.page.locator('#SOAPPlanid').fill(plan);
});

await test.step('And I click the submit button', async () => {
await chartPage.page.getByRole('button', { name: /save and close/i }).click();
});

await test.step('Then I should see a success notification', async () => {
await expect(chartPage.page.getByText(/the form has been submitted successfully/i)).toBeVisible();
});

await test.step('And if I navigate to the visits dashboard', async () => {
await visitsPage.goTo(patient.uuid);
});

await test.step('Then I should the newly filled form in the encounters table', async () => {
await expect(visitsPage.page.getByRole('tab', { name: /visit summaries/i })).toBeVisible();
await expect(visitsPage.page.getByRole('tab', { name: /all encounters/i })).toBeVisible();

await visitsPage.page.getByRole('tab', { name: /^encounters$/i }).click();

const headerRow = visitsPage.page.getByRole('table').locator('thead > tr');

await expect(headerRow).toContainText(/date & time/i);
await expect(headerRow).toContainText(/encounter type/i);
await expect(headerRow).toContainText(/provider/i);

await visitsPage.page.getByRole('table').locator('th#expand').click();

await expect(visitsPage.page.getByText(subjectiveFindings)).toBeVisible();
await expect(visitsPage.page.getByText(objectiveFindings)).toBeVisible();
await expect(visitsPage.page.getByText(assessment)).toBeVisible();
await expect(visitsPage.page.getByText(plan)).toBeVisible();
});
});

test.afterEach(async ({ api }) => {
await endVisit(api, visit.uuid);
await deletePatient(api, patient.uuid);
});
6 changes: 5 additions & 1 deletion e2e/support/github/run-e2e-docker-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
working_dir=$(mktemp -d "${TMPDIR:-/tmp/}openmrs-e2e-frontends.XXXXXXXXXX")
# get a list of all the apps in this workspace
apps=$(yarn workspaces list --json | jq -r 'if ((.location == ".") or (.location | test("-app") | not)) then halt else .name end')

# Remove "esm-form-engine-app" from the list
apps=$(echo "$apps" | grep -v "esm-form-engine-app")

# this array will hold all of the packed app names
app_names=()

Expand All @@ -20,7 +24,7 @@ do
# run yarn pack for our app and add it to the working directory
yarn workspace "$app" pack -o "$working_dir/$app_name.tgz" >/dev/null;
done;
echo "Created packed app archives"
echo "Created packed app archives"

echo "Creating dynamic spa-assemble-config.json..."
# dynamically assemble our list of frontend modules, prepending the login app and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export const SiderailNavButton: React.FC<SiderailNavButtonProps> = ({
return (
<IconButton
align="left"
aria-label={iconDescription}
className={classNames(styles.container, {
[styles.active]: isWorkspaceActive,
})}
Expand Down

0 comments on commit 0c20c49

Please sign in to comment.