Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(e2e) Test clinical forms workflow #1504

Merged
merged 7 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading