Skip to content
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
87 changes: 87 additions & 0 deletions e2e/pages/bed-management-page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { expect, type Page } from '@playwright/test';
import { step, test } from '../core';

export class BedManagementPage {
private constructor(readonly page: Page) {}

readonly firstAddBedButton = () => this.page.locator('.bed-layout .block.add-block').first();
readonly bedNumberField = () => this.page.locator('#bed-number-field');
readonly saveButton = () => this.page.getByRole('button', { name: 'Save', exact: true });

locationBlock(locationName: string) {
return this.page.locator('.location.block').filter({ hasText: locationName });
}

bedBlock(bedNumber: string) {
return this.page.locator('.existing-bed').filter({ hasText: bedNumber });
}

deleteBedButton(bedNumber: string) {
return this.bedBlock(bedNumber).locator('a[title="delete"]');
}

@step
static async open(page: Page) {
return test.step('When I navigate to the bed management admission locations page', async () => {
const bedManagementPage = new BedManagementPage(page);
await page.goto('/openmrs/owa/bedmanagement/admissionLocations.html');
return bedManagementPage;
});
}

@step
async selectLocation(locationName: string) {
return test.step(`When I select the "${locationName}" location`, async () => {
await this.locationBlock(locationName).click();
});
}

/**
* Opens the first "Add Bed" slot and saves it with the given bed number.
* Returns the bed number actually saved (the field truncates input beyond its maxlength).
*/
@step
async addBed(bedNumber: string) {
return test.step(`When I add a new bed with number "${bedNumber}"`, async () => {
await this.firstAddBedButton().click();
await this.bedNumberField().fill(bedNumber);
const savedBedNumber = await this.bedNumberField().inputValue();
await this.saveButton().click();
return savedBedNumber;
});
}

@step
async expectBedCreated(bedNumber: string) {
return test.step(`Then I should see bed "${bedNumber}" displayed`, async () => {
await expect(this.bedBlock(bedNumber)).toBeVisible();
});
}

/**
* Hovers over the bed to reveal its delete button (hidden until hover), clicks it,
* and accepts the native JS confirm dialog that follows.
*/
@step
async deleteBed(bedNumber: string) {
return test.step(`When I delete bed "${bedNumber}"`, async () => {
this.page.once('dialog', (dialog) => dialog.accept());
await this.bedBlock(bedNumber).hover();
await this.deleteBedButton(bedNumber).click();
});
}

@step
async expectDeletedSuccessfullyNotification() {
return test.step('Then I should see a "Deleted successfully" notification', async () => {
await expect(this.page.getByText('Deleted successfully')).toBeVisible();
});
}

@step
async expectBedDeleted(bedNumber: string) {
return test.step(`Then bed "${bedNumber}" should no longer be displayed`, async () => {
await expect(this.bedBlock(bedNumber)).not.toBeVisible();
});
}
}
1 change: 1 addition & 0 deletions e2e/pages/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './dispensing-page';
export * from './ward-page';
export * from './service-queues-page';
export * from './bed-management-page';
32 changes: 25 additions & 7 deletions e2e/pages/ward-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export class WardPage {
static async open(page: Page) {
return test.step('When I navigate to the ward page', async () => {
const wardPage = new WardPage(page);
wardPage.page.goto('/openmrs/spa/home/ward');
await wardPage.page.goto('/openmrs/spa/home/ward');
return wardPage;
});
}
Expand Down Expand Up @@ -107,12 +107,16 @@ export class WardPage {

@step
async selectBed(bedNumber: string) {
return test.step(`When I select bed ${bedNumber} for the patient admission`, async () => {
if (await this.page.getByRole('combobox', { name: 'Choose an option' }).isVisible()) {
await this.page.getByRole('combobox', { name: 'Choose an option' }).click();
}
await this.page.getByText(new RegExp(`^${bedNumber} · `)).click();
});
// if the ward contains many beds, the bed selection will be a dropdown instead of radio buttons. Handle both cases.
const bedDropdown = this.page.getByRole('combobox', { name: 'Choose an option' });
const isDropdownVisible = await bedDropdown
.waitFor({ state: 'visible', timeout: 2000 })
.then(() => true)
.catch(() => false);
if (isDropdownVisible) {
await bedDropdown.click();
}
await this.page.getByText(new RegExp(`^${bedNumber} · `)).click();
}

@step
Expand Down Expand Up @@ -203,4 +207,18 @@ export class WardPage {
await expect(this.page.getByText('admission request cancelled')).toBeVisible();
});
}

@step
async expectBedNumber(bedNumber: string) {
return test.step(`Then I should see bed number ${bedNumber} displayed`, async () => {
await expect(this.page.getByText(bedNumber, { exact: true })).toBeVisible();
});
}

@step
async expectBedNumberNotVisible(bedNumber: string) {
return test.step(`Then I should not see bed number ${bedNumber} displayed`, async () => {
await expect(this.page.getByText(bedNumber, { exact: true })).not.toBeVisible();
});
}
}
36 changes: 36 additions & 0 deletions e2e/specs/bed-management/bed-management.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { changeLocation } from '../../commands';
import { KGHLocationsUuids, test } from '../../core';
import { BedManagementPage, WardPage } from '../../pages';

test.describe('Bed Management', () => {
test.beforeEach(async ({ api }) => {
await changeLocation(api, KGHLocationsUuids['MCOE Triage']);
});

test('Add a bed via bed mangement, then remove it', async ({ page }) => {
const randomFourDigitNumber = Math.floor(1000 + Math.random() * 9000);
const bedNumber = `TestBed${randomFourDigitNumber}`;

let bedManagementPage = await BedManagementPage.open(page);
await bedManagementPage.selectLocation('MCOE Triage');

const savedBedNumber = await bedManagementPage.addBed(bedNumber);

await bedManagementPage.expectBedCreated(savedBedNumber);

// go to the ward page and confirm the bed is displayed there as well
let wardPage = await WardPage.open(page);
await wardPage.expectBedNumber(savedBedNumber);

bedManagementPage = await BedManagementPage.open(page);
await bedManagementPage.selectLocation('MCOE Triage');

await bedManagementPage.deleteBed(savedBedNumber);
await bedManagementPage.expectDeletedSuccessfullyNotification();
await bedManagementPage.expectBedDeleted(savedBedNumber);

// go to the ward page and confirm the bed is no longer displayed there as well
wardPage = await WardPage.open(page);
await wardPage.expectBedNumberNotVisible(savedBedNumber);
});
});
18 changes: 17 additions & 1 deletion e2e/specs/ward/ward-admission.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ test.describe('Ward App', () => {
await changeLocation(api, KGHLocationsUuids['MCOE Triage']);
});

test('Admit a patient to a ward from the admission requests list, then transfer to another location', async ({
test('Admit a patient to a ward from the admission requests list, then transfer to another location, then create transfer request to yet another location and cancel it', async ({
page,
api,
adultWoman,
Expand Down Expand Up @@ -51,6 +51,22 @@ test.describe('Ward App', () => {
await antenatalWardPage.expectAdmissionSuccessNotification(patientName, bedNumber);

await wardPage.expectPatientAdmittedToWard(adultWoman);

await wardPage.patientCard(patientName).click();
await wardPage.transfersButton().click();
await wardPage.selectLocation('Triage | MCOE');
await wardPage.clickSaveButton();
await wardPage.expectTransferRequestSubmitted(patientName);

await changeLocation(api, KGHLocationsUuids['MCOE Triage']);
const mcoeTriageWardPage = await WardPage.open(page);
await mcoeTriageWardPage.manageAdmissionRequests().click();
await wardPage.cancelAdmissionButton(patientName).click();

await wardPage.clinicalNotesField().fill('Patient does not require transfer at this time');
await wardPage.clickSaveButton();

await wardPage.expectAdmissionRequestCancelled();
});

test('Cancel a patient admission request from the ward admission requests list', async ({
Expand Down
Loading