diff --git a/.env b/.env index e3d584e6..c43af12b 100644 --- a/.env +++ b/.env @@ -19,6 +19,11 @@ O3_URL_DEV=https://ozone-dev.mekomsolutions.net O3_URL_QA=https://ozone-qa.mekomsolutions.net O3_URL_DEMO=https://demo.ozone-his.com +# ERPNEXT +ERPNEXT_URL_DEV=https://erpnext.ozone-dev.mekomsolutions.net +ERPNEXT_URL_QA= +ERPNEXT_URL_DEMO= + # Odoo ODOO_URL_DEV=https://erp.ozone-dev.mekomsolutions.net ODOO_URL_QA=https://erp.ozone-qa.mekomsolutions.net @@ -47,6 +52,10 @@ KEYCLOAK_URL_DEMO=https://auth.demo.ozone-his.com O3_USERNAME_ON_FOSS=admin O3_PASSWORD_ON_FOSS=Admin123 +# ERPNext test user credentials +ERPNEXT_USERNAME=Administrator +ERPNEXT_PASSWORD=password + # Odoo test user credentials for FOSS ODOO_USERNAME_ON_FOSS=admin ODOO_PASSWORD_ON_FOSS=admin diff --git a/e2e/tests/erpnext-openmrs-flows.spec.ts b/e2e/tests/erpnext-openmrs-flows.spec.ts new file mode 100644 index 00000000..893776b2 --- /dev/null +++ b/e2e/tests/erpnext-openmrs-flows.spec.ts @@ -0,0 +1,131 @@ +import { test, expect } from '@playwright/test'; +import { ERPNext } from '../utils/functions/erpnext'; +import { O3_URL, ERPNEXT_URL } from '../utils/configs/globalSetup'; +import { OpenMRS, patientName } from '../utils/functions/openmrs'; + +let openmrs: OpenMRS; +let erpnext: ERPNext; + +test.beforeEach(async ({ page }) => { + openmrs = new OpenMRS(page); + erpnext = new ERPNext(page); + + await openmrs.login(); + await expect(page).toHaveURL(/.*home/); + await openmrs.createPatient(); + await openmrs.startPatientVisit(); +}); + +test('Ordering a lab test for an OpenMRS patient creates the corresponding ERPNext customer.', async ({ page }) => { + // replay + await openmrs.createLabOrder(); + + // verify + await erpnext.open(); + await expect(page).toHaveURL(/.*home/); + await erpnext.searchCustomer(); + const customer = await page.locator(".bold a:nth-child(1)"); + await expect(customer).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); +}); + +test('Ordering a drug for an OpenMRS patient creates the corresponding ERPNext customer with a filled quotation.', async ({ page }) => { + // replay + await openmrs.createDrugOrder(); + + // verify + await erpnext.open(); + await expect(page).toHaveURL(/.*home/); + await erpnext.searchCustomer(); + const customer = await page.locator(".bold a:nth-child(1)"); + await expect(customer).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); + await page.getByRole('link', { name: `${patientName.firstName + ' ' + patientName.givenName}` }).click(); + await page.locator('#customer-dashboard_tab-tab').click(); + await page.getByLabel('Dashboard').getByText('Quotation').click(); + await erpnext.searchQuotation(); + await expect(page.getByText('Draft').nth(0)).toBeVisible(); +}); + +test('Ending an OpenMRS patient visit with a synced drug order updates the corresponding ERPNext draft quotation to an open state.', async ({ page }) => { + // setup + await openmrs.createDrugOrder(); + await erpnext.open(); + await expect(page).toHaveURL(/.*home/); + await erpnext.searchQuotation(); + + const quotationStatus = await page.locator('div.level-left.ellipsis div:nth-child(3) span span'); + await expect(quotationStatus).toHaveText('Draft'); + + // replay + await page.goto(`${O3_URL}`); + await openmrs.searchPatient(`${patientName.firstName + ' ' + patientName.givenName}`); + await openmrs.endPatientVisit(); + + // verify + await page.goto(`${ERPNEXT_URL}/app/home`); + await erpnext.searchQuotation(); + await expect(quotationStatus).toHaveText('Open'); +}); + +test('Revising a synced OpenMRS drug order edits the corresponding ERPNext quotation line.', async ({ page }) => { + // setup + await openmrs.createDrugOrder(); + await erpnext.open(); + await expect(page).toHaveURL(/.*home/); + await erpnext.searchQuotation(); + await page.getByRole('link', { name: `${patientName.firstName + ' ' + patientName.givenName}` }).click(); + const quantity = await page.locator("div.bold:nth-child(4) div:nth-child(2) div"); + await expect(quantity).toHaveText('12'); + + // replay + await page.goto(`${O3_URL}`); + await openmrs.searchPatient(`${patientName.firstName + ' ' + patientName.givenName}`); + await openmrs.editDrugOrder(); + + // verify + await page.goto(`${ERPNEXT_URL}/app/home`); + await erpnext.searchQuotation(); + await page.getByRole('link', { name: `${patientName.firstName + ' ' + patientName.givenName}` }).click(); + await expect(quantity).toHaveText('8'); +}); + +test('Ordering a drug with a free text medication dosage for an OpenMRS patient creates the corresponding ERPNext customer with a filled quotation.', async ({ page }) => { + // replay + await openmrs.createDrugOrderWithFreeTextDosage(); + + // verify + await erpnext.open(); + await expect(page).toHaveURL(/.*home/); + await erpnext.searchCustomer(); + const customer = await page.locator(".bold a:nth-child(1)"); + await expect(customer).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); + await page.getByRole('link', { name: `${patientName.firstName + ' ' + patientName.givenName}` }).click(); + await page.locator('#customer-dashboard_tab-tab').click(); + await page.getByLabel('Dashboard').getByText('Quotation').click(); + await erpnext.searchQuotation(); + await expect(page.getByText('Draft').nth(0)).toBeVisible(); +}); + +test('Discontinuing a synced OpenMRS drug order for an ERPNext customer removes the corresponding quotation.', async ({ page }) => { + // setup + await openmrs.createDrugOrder(); + await erpnext.open(); + await expect(page).toHaveURL(/.*home/); + await erpnext.searchQuotation(); + await expect(page.getByText(`${patientName.firstName + ' ' + patientName.givenName}`)).toBeVisible(); + + // replay + await page.goto(`${O3_URL}`); + await openmrs.searchPatient(`${patientName.firstName + ' ' + patientName.givenName}`); + await openmrs.discontinueDrugOrder(); + + // verify + await page.goto(`${ERPNEXT_URL}/app/home`); + await erpnext.searchQuotation(); + await expect(page.getByText(`${patientName.firstName + ' ' + patientName.givenName}`)).not.toBeVisible(); + await expect(page.getByText('No Quotation found')).toBeVisible(); +}); + +test.afterEach(async ({ page }) => { + await openmrs.deletePatient(); + await page.close(); +}); diff --git a/e2e/tests/odoo-openmrs-flows.spec.ts b/e2e/tests/odoo-openmrs-flows.spec.ts index 8f118796..7e9ca649 100644 --- a/e2e/tests/odoo-openmrs-flows.spec.ts +++ b/e2e/tests/odoo-openmrs-flows.spec.ts @@ -148,7 +148,6 @@ test('Discontinuing a synced OpenMRS drug order for an Odoo customer with a sing await expect(QuotationItem).not.toHaveText('Aspirin 325mg'); }); - test('Discontinuing a synced OpenMRS drug order for an Odoo customer with multiple quotation lines removes the corresponding quoatation.', async ({ page }) => { // setup await openmrs.goToLabOrderForm(); diff --git a/e2e/utils/configs/globalSetup.ts b/e2e/utils/configs/globalSetup.ts index 0587d5a4..90dcb12e 100644 --- a/e2e/utils/configs/globalSetup.ts +++ b/e2e/utils/configs/globalSetup.ts @@ -12,6 +12,7 @@ import { dotenv.config(); export const O3_URL = `${process.env.TEST_ENVIRONMENT}` == 'demo' ? `${process.env.O3_URL_DEMO}` : `${process.env.TEST_ENVIRONMENT}` == 'qa' ? `${process.env.O3_URL_QA}`: `${process.env.O3_URL_DEV}`; +export const ERPNEXT_URL = `${process.env.TEST_ENVIRONMENT}` == 'demo' ? `${process.env.ERPNEXT_URL_DEMO}` : `${process.env.TEST_ENVIRONMENT}` == 'qa' ? `${process.env.ERPNEXT_URL_QA}`: `${process.env.ERPNEXT_URL_DEV}`; export const ODOO_URL = `${process.env.TEST_ENVIRONMENT}` == 'demo' ? `${process.env.ODOO_URL_DEMO}` : `${process.env.TEST_ENVIRONMENT}` == 'qa' ? `${process.env.ODOO_URL_QA}`: `${process.env.ODOO_URL_DEV}`; export const SENAITE_URL = `${process.env.TEST_ENVIRONMENT}` == 'demo' ? `${process.env.SENAITE_URL_DEMO}` : `${process.env.TEST_ENVIRONMENT}` == 'qa' ? `${process.env.SENAITE_URL_QA}`: `${process.env.SENAITE_URL_DEV}`; export const KEYCLOAK_URL = `${process.env.TEST_ENVIRONMENT}` == 'demo' ? `${process.env.KEYCLOAK_URL_DEMO}` : `${process.env.TEST_ENVIRONMENT}` == 'qa' ? `${process.env.KEYCLOAK_URL_QA}`: `${process.env.KEYCLOAK_URL_DEV}`; diff --git a/e2e/utils/functions/erpnext.ts b/e2e/utils/functions/erpnext.ts new file mode 100644 index 00000000..b421adb5 --- /dev/null +++ b/e2e/utils/functions/erpnext.ts @@ -0,0 +1,31 @@ +import { Page } from '@playwright/test'; +import { delay, patientName } from './openmrs'; +import { ERPNEXT_URL } from '../configs/globalSetup'; + +export class ERPNext { + constructor(readonly page: Page) {} + + async open() { + await this.page.goto(`${ERPNEXT_URL}`); + await this.page.locator('input#login_email').fill(`${process.env.ERPNEXT_USERNAME}`); + await this.page.locator('input#login_password').fill(`${process.env.ERPNEXT_PASSWORD}`); + await this.page.locator('button.btn-login').click(); + } + + async searchCustomer() { + await this.page.getByRole('link', { name: /selling/i }).click(); + await this.page.getByRole('link', { name: 'Customer', exact: true }).click(); + await this.page.getByPlaceholder('Customer Name').clear(); + await this.page.getByPlaceholder(/customer name/i).fill(`${patientName.givenName}`); + await delay(3000); + } + + async searchQuotation() { + await this.page.getByRole('link', { name: /selling/i }).click(); + await this.page.getByRole('link', { name: 'Quotation', exact: true }).click(); + await this.page.getByPlaceholder(/title/i).clear(); + await this.page.getByPlaceholder(/party/i).clear(); + await this.page.getByPlaceholder(/title/i).fill(`${patientName.givenName}`); + await delay(3000); + } +} diff --git a/e2e/utils/functions/openmrs.ts b/e2e/utils/functions/openmrs.ts index 6f90019d..3fe511e8 100644 --- a/e2e/utils/functions/openmrs.ts +++ b/e2e/utils/functions/openmrs.ts @@ -137,12 +137,12 @@ export class OpenMRS { } async endPatientVisit() { - await this.searchPatient(`${patientFullName}`) + await this.searchPatient(`${patientName.firstName + ' ' + patientName.givenName}`) await this.page.getByRole('button', { name: 'Actions', exact: true }).click(); await this.page.getByRole('menuitem', { name: 'End visit' }).click(); await this.page.getByRole('button', { name: 'danger End Visit' }).click(); await expect(this.page.getByText('Visit ended')).toBeVisible(); - await this.page.getByRole('button', { name: 'Close' }).click(); + await this.page.getByRole('button', { name: 'Close', exact: true }).click(); } async deletePatient() { @@ -201,6 +201,18 @@ export class OpenMRS { await expect(appointmentStatus).toHaveText('Scheduled'); } + async createLabOrder() { + await this.page.getByLabel('Order basket', { exact: true }).click(); + await this.page.getByRole('button', { name: 'Add', exact: true }).nth(1).click(); + await this.page.getByPlaceholder('Search for a test type').fill('Urobilinogen'); + await delay(3000); + await this.page.getByRole('button', { name: 'Order form' }).click(); + await this.page.getByRole('button', { name: 'Save order' }).click(); + await this.page.getByRole('button', { name: 'Sign and close' }).click(); + await expect(this.page.getByText('Placed orders')).toBeVisible(); + await delay(3000); + } + async goToLabOrderForm() { await this.page.getByLabel('Clinical forms').click(); await delay(3000); @@ -245,12 +257,12 @@ export class OpenMRS { async createDrugOrder() { await this.page.getByLabel('Order basket', { exact: true }).click(); - await delay(3000); + await delay(2000); await this.page.getByRole('button', { name: 'Add', exact: true }).nth(0).click(); await delay(2000); await this.page.getByPlaceholder('Search for a drug or orderset (e.g. "Aspirin")').fill('Aspirin 325mg'); await this.page.getByRole('button', { name: 'Order form' }).click(); - await delay(4000); + await delay(2000); await this.page.getByPlaceholder('Dose').fill('4'); await this.page.getByRole('button', { name: 'Open', exact: true }).nth(1).click(); await this.page.getByText('Intravenous', {exact: true}).click(); @@ -303,6 +315,8 @@ export class OpenMRS { await this.page.getByText('Thrice daily').click(); await this.page.getByLabel('Duration', { exact: true }).clear(); await this.page.getByLabel('Duration', { exact: true }).fill('6'); + await this.page.getByLabel('Quantity to dispense').clear(); + await this.page.getByLabel('Quantity to dispense').fill('8'); await this.page.getByRole('button', { name: 'Save order' }).focus(); await this.page.getByRole('button', { name: 'Save order' }).dispatchEvent('click'); await expect(this.page.getByText('Sign and close')).toBeVisible(); diff --git a/package.json b/package.json index fed2a293..10c0aeaa 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "!playwright-report/" ], "scripts": { - "e2e-tests-pro": "npx playwright test", + "e2e-tests-pro": "npx playwright test erpnext-openmrs", "e2e-tests-foss": "npx playwright test odoo-openmrs openmrs-senaite" }, "publishConfig": {