diff --git a/e2e/tests/odoo-openmrs-flows.spec.ts b/e2e/tests/odoo-openmrs-flows.spec.ts index ca64d1a..f46b7aa 100644 --- a/e2e/tests/odoo-openmrs-flows.spec.ts +++ b/e2e/tests/odoo-openmrs-flows.spec.ts @@ -23,6 +23,7 @@ test('Ordering a lab test for an OpenMRS patient creates the corresponding Odoo // verify await odoo.open(); + await odoo.navigateToSales(); await odoo.searchCustomer(); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(4)')).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(8) span')).toHaveText('Quotation'); @@ -34,6 +35,7 @@ test('Editing the details of an OpenMRS patient with a synced lab order edits th await page.getByPlaceholder('Search for a test type').fill('Blood urea nitrogen'); await openmrs.saveLabOrder(); await odoo.open(); + await odoo.navigateToSales(); await odoo.searchCustomer(); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(4)')).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(8) span')).toHaveText('Quotation'); @@ -45,6 +47,7 @@ test('Editing the details of an OpenMRS patient with a synced lab order edits th // verify await page.goto(`${ODOO_URL}`); + await odoo.navigateToSales(); await odoo.searchCustomer(); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(4)')).toHaveText(`${patientName.updatedFirstName}` + ' ' + `${patientName.givenName}`); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(8) span')).toHaveText('Quotation'); @@ -59,6 +62,7 @@ test('Ordering a drug for an OpenMRS patient creates the corresponding Odoo cust // verify await odoo.open(); + await odoo.navigateToSales(); await odoo.searchCustomer(); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(4)')).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(8) span')).toHaveText('Quotation'); @@ -71,6 +75,7 @@ test('Editing the details of an OpenMRS patient with a synced drug order edits t await openmrs.fillDrugOrderForm(); await openmrs.saveDrugOrder(); await odoo.open(); + await odoo.navigateToSales(); await odoo.searchCustomer(); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(4)')).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(8) span')).toHaveText('Quotation'); @@ -82,6 +87,7 @@ test('Editing the details of an OpenMRS patient with a synced drug order edits t // verify await page.goto(`${ODOO_URL}`); + await odoo.navigateToSales(); await odoo.searchCustomer(); await expect(page.locator('table tbody td.o_data_cell:nth-child(4)')).toHaveText(`${patientName.updatedFirstName}` + ' ' + `${patientName.givenName }`); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(8) span')).toHaveText('Quotation'); @@ -94,6 +100,7 @@ test('Revising a synced OpenMRS drug order edits the corresponding Odoo quotatio await openmrs.fillDrugOrderForm(); await openmrs.saveDrugOrder(); await odoo.open(); + await odoo.navigateToSales(); await odoo.searchCustomer(); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(4)')).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); await page.getByRole('cell', { name: `${patientName.firstName + ' ' + patientName.givenName}` }).click(); @@ -108,6 +115,7 @@ test('Revising a synced OpenMRS drug order edits the corresponding Odoo quotatio // verify await page.goto(`${ODOO_URL}`); + await odoo.navigateToSales(); await odoo.searchCustomer(); await page.getByRole('cell', { name: `${patientName.firstName + ' ' + patientName.givenName}` }).click(); await expect(drugOrderItem).toContainText('8.0 Tablet'); @@ -121,6 +129,7 @@ test('Discontinuing a synced OpenMRS drug order for an Odoo customer with a sing await openmrs.fillDrugOrderForm(); await openmrs.saveDrugOrder(); await odoo.open(); + await odoo.navigateToSales(); await odoo.searchCustomer(); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(4)')).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(8) span')).toHaveText('Quotation'); @@ -134,6 +143,7 @@ test('Discontinuing a synced OpenMRS drug order for an Odoo customer with a sing // verify await page.goto(`${ODOO_URL}`); + await odoo.navigateToSales(); await odoo.searchCustomer(); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(4)')).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(8) span')).toHaveText('Cancelled'); @@ -152,6 +162,7 @@ test('Discontinuing a synced OpenMRS drug order for an Odoo customer with multip await openmrs.fillDrugOrderForm(); await openmrs.saveDrugOrder(); await odoo.open(); + await odoo.navigateToSales(); await odoo.searchCustomer(); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(4)')).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(8) span')).toHaveText('Quotation'); @@ -166,6 +177,7 @@ test('Discontinuing a synced OpenMRS drug order for an Odoo customer with multip // verify await page.goto(`${ODOO_URL}`); + await odoo.navigateToSales(); await odoo.searchCustomer(); await page.getByRole('cell', { name: `${patientName.firstName + ' ' + patientName.givenName}` }).click(); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(2) span:nth-child(1) span')).toHaveText('Blood urea nitrogen'); @@ -178,6 +190,7 @@ test('Ordering a drug with a free text medication dosage for an OpenMRS patient // verify await odoo.open(); + await odoo.navigateToSales(); await odoo.searchCustomer(); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(4)')).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(8) span')).toHaveText('Quotation'); @@ -189,6 +202,7 @@ test('Discontinuing a synced OpenMRS lab order for an Odoo customer with a singl await page.getByPlaceholder('Search for a test type').fill('Blood urea nitrogen'); await openmrs.saveLabOrder(); await odoo.open(); + await odoo.navigateToSales(); await odoo.searchCustomer(); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(4)')).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(8) span')).toHaveText('Quotation'); @@ -201,6 +215,7 @@ test('Discontinuing a synced OpenMRS lab order for an Odoo customer with a singl // verify await page.goto(`${ODOO_URL}`); + await odoo.navigateToSales(); await odoo.searchCustomer(); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(4)')).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(8) span')).toHaveText('Cancelled'); diff --git a/e2e/tests/odoo-superset-flows.spec.ts b/e2e/tests/odoo-superset-flows.spec.ts new file mode 100644 index 0000000..a0c8e42 --- /dev/null +++ b/e2e/tests/odoo-superset-flows.spec.ts @@ -0,0 +1,119 @@ +import { test, expect } from '@playwright/test'; +import { Odoo } from '../utils/functions/odoo'; +import { Superset } from '../utils/functions/superset'; +import { OpenMRS, patientName } from '../utils/functions/openmrs'; +import { O3_URL, SUPERSET_URL } from '../utils/configs/globalSetup'; + +let odoo: Odoo; +let openmrs: OpenMRS; +let superset: Superset; + +test.beforeEach(async ({ page }) => { + openmrs = new OpenMRS(page); + odoo = new Odoo(page); + superset = new Superset(page); + + await openmrs.login(); + await openmrs.createPatient(); + await openmrs.startPatientVisit(); +}); + +test(`Creating an Odoo sale order line generates an entry in Superset's sale_order_lines table.`, async ({ page }) => { + // setup + await openmrs.searchPatient(`${patientName.firstName + ' ' + patientName.givenName}`); + await openmrs.goToLabOrderForm(); + await page.getByPlaceholder('Search for a test type').fill('Complete blood count'); + await openmrs.saveLabOrder(); + await superset.open(); + await superset.selectDBSchema(); + await superset.clearSQLEditor(); + let saleOrderLinesCountQuery = `SELECT COUNT (*) FROM sale_order_lines;`; + await page.getByRole('textbox').first().fill(saleOrderLinesCountQuery); + await superset.runSQLQuery(); + let initialSaleOrderLinesCount = Number(await page.locator('div.virtual-table-cell').textContent()); + await page.getByRole('tab', { name: 'Query history' }).click(); + await superset.clearSQLEditor(); + + // replay + await odoo.open(); + await odoo.navigateToSales(); + await odoo.createSaleOrderLine(); + const salesOrderId = await page.locator('.oe_title h1:nth-child(1) span').textContent(); + await expect(page.locator('table tbody td.o_data_cell:nth-child(2) span:nth-child(1) span')).toHaveText('Acétaminophene Co 500mg'); + + // verify + await page.goto(`${SUPERSET_URL}/sqllab`); + await superset.clearSQLEditor(); + await page.getByRole('textbox').first().fill(saleOrderLinesCountQuery); + await superset.runSQLQuery(); + let updatedSaleOrderLinesCount = Number(await page.locator('div.virtual-table-cell').textContent()); + await expect(updatedSaleOrderLinesCount).toBe(initialSaleOrderLinesCount + 1); + await page.getByRole('tab', { name: 'Query history' }).click(); + await superset.clearSQLEditor(); + let saleOrderLinesQuery = `SELECT sale_order_name, customer_name, product_name, quantity, unit_price FROM sale_order_lines WHERE sale_order_name like '${salesOrderId}';`; + await page.getByRole('textbox').first().fill(saleOrderLinesQuery); + await superset.runSQLQuery(); + await expect(page.locator('div.virtual-table-cell:nth-child(1)')).toHaveText(`${salesOrderId}`); + await expect(page.locator('div.virtual-table-cell:nth-child(2)')).toHaveText(`${patientName.firstName + ' ' + patientName.givenName}`); + await expect(page.locator('div.virtual-table-cell:nth-child(3)')).toHaveText('Acétaminophene Co 500mg'); + let quantity = Number(await page.locator('div.virtual-table-cell:nth-child(4)').textContent()); + let unitPrice = Number(await page.locator('div.virtual-table-cell:nth-child(5)').textContent()); + await expect(quantity).toBe(8); + await expect(unitPrice).toBe(2); +}); + +test(`A (synced) sale order line in Odoo generates an entry in Superset's sale_order_lines table.`, async ({ page }) => { + // setup + await superset.open(); + await superset.selectDBSchema(); + await superset.clearSQLEditor(); + let saleOrderLinesCountQuery = `SELECT COUNT (*) FROM sale_order_lines;`; + await page.getByRole('textbox').first().fill(saleOrderLinesCountQuery); + await superset.runSQLQuery(); + let initialSaleOrderLinesCount = Number(await page.locator('div.virtual-table-cell').textContent()); + await page.getByRole('tab', { name: 'Query history' }).click(); + await superset.clearSQLEditor(); + await page.goto(`${O3_URL}`); + await openmrs.searchPatient(`${patientName.firstName + ' ' + patientName.givenName}`); + await openmrs.goToLabOrderForm(); + await page.getByPlaceholder('Search for a test type').fill('Haemoglobin'); + await openmrs.saveLabOrder(); + + // replay + await odoo.open(); + await odoo.navigateToSales(); + await odoo.searchCustomer(); + await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(4)')).toContainText(`${patientName.firstName + ' ' + patientName.givenName}`); + await expect(page.locator('tr.o_data_row:nth-child(1) td:nth-child(8) span')).toHaveText('Quotation'); + await page.getByRole('cell', { name: `${patientName.firstName + ' ' + patientName.givenName}` }).click(); + const salesOrderId = await page.locator('.oe_title h1:nth-child(1) span').textContent(); + await expect(page.locator('table tbody td.o_data_cell:nth-child(2) span:nth-child(1) span')).toHaveText('Haemoglobin'); + let quantity = Number(await page.locator('td.o_data_cell:nth-child(4)').textContent()); + await expect(quantity).toBe(1); + await expect(page.locator('td.o_data_cell:nth-child(7)')).toContainText('24'); + + // verify + await page.goto(`${SUPERSET_URL}/sqllab`); + await superset.clearSQLEditor(); + await page.getByRole('textbox').first().fill(saleOrderLinesCountQuery); + await superset.runSQLQuery(); + let updatedSaleOrderLinesCount = Number(await page.locator('div.virtual-table-cell').textContent()); + await expect(updatedSaleOrderLinesCount).toBe(initialSaleOrderLinesCount + 1); + await page.getByRole('tab', { name: 'Query history' }).click(); + await superset.clearSQLEditor(); + let saleOrderLinesQuery = `SELECT sale_order_name, customer_name, product_name, quantity, unit_price FROM sale_order_lines WHERE sale_order_name like '${salesOrderId}';`; + await page.getByRole('textbox').first().fill(saleOrderLinesQuery); + await superset.runSQLQuery(); + await expect(page.locator('div.virtual-table-cell:nth-child(1)')).toHaveText(`${salesOrderId}`); + await expect(page.locator('div.virtual-table-cell:nth-child(2)')).toHaveText(`${patientName.firstName + ' ' + patientName.givenName}`); + await expect(page.locator('div.virtual-table-cell:nth-child(3)')).toHaveText('Haemoglobin'); + quantity = Number(await page.locator('div.virtual-table-cell:nth-child(4)').textContent()); + let unitPrice = Number(await page.locator('div.virtual-table-cell:nth-child(5)').textContent()); + await expect(quantity).toBe(1); + await expect(unitPrice).toBe(24); +}); + +test.afterEach(async ({ page }) => { + await openmrs.voidPatient(); + await page.close(); +}); diff --git a/e2e/tests/openmrs-superset-flows.spec.ts b/e2e/tests/openmrs-superset-flows.spec.ts index 997f6e5..0d36b48 100644 --- a/e2e/tests/openmrs-superset-flows.spec.ts +++ b/e2e/tests/openmrs-superset-flows.spec.ts @@ -13,7 +13,7 @@ test.beforeEach(async ({ page }) => { await openmrs.login(); }); -test('Creating an OpenMRS patient creates the patient in Superset patients table.', async ({ page }) => { +test(`Creating an OpenMRS patient creates the patient in Superset's patients table.`, async ({ page }) => { // setup await superset.open(); await superset.selectDBSchema(); @@ -51,7 +51,7 @@ test('Creating an OpenMRS patient creates the patient in Superset patients table await openmrs.voidPatient(); }); -test('Creating an OpenMRS visit creates the visit in Superset visits table.', async ({ page }) => { +test(`Creating an OpenMRS visit creates the visit in Superset's visits table.`, async ({ page }) => { // setup await openmrs.createPatient(); await superset.open(); @@ -90,7 +90,7 @@ test('Creating an OpenMRS visit creates the visit in Superset visits table.', as await openmrs.voidPatient(); }); -test('Creating an OpenMRS order creates the order in Superset orders table.', async ({ page }) => { +test(`Creating an OpenMRS order creates the order in Superset's orders table.`, async ({ page }) => { // setup await openmrs.createPatient(); await openmrs.searchPatientId(); @@ -138,7 +138,7 @@ test('Creating an OpenMRS order creates the order in Superset orders table.', as await openmrs.voidPatient(); }); -test('Creating an OpenMRS encounter creates the encounter in Superset encounters table.', async ({ page }) => { +test(`Creating an OpenMRS encounter creates the encounter in Superset's encounters table.`, async ({ page }) => { // setup await openmrs.createPatient(); await openmrs.searchPatientId(); @@ -186,7 +186,7 @@ test('Creating an OpenMRS encounter creates the encounter in Superset encounters await openmrs.voidPatient(); }); -test('Creating an OpenMRS condition creates the condition in Superset conditions table.', async ({ page }) => { +test(`Creating an OpenMRS condition creates the condition in Superset's conditions table.`, async ({ page }) => { // setup await openmrs.createPatient(); await openmrs.searchPatientId(); @@ -232,7 +232,7 @@ test('Creating an OpenMRS condition creates the condition in Superset conditions await openmrs.voidPatient(); }); -test('Creating an OpenMRS obs creates the observation in Superset observations table.', async ({ page }) => { +test(`Creating an OpenMRS obs creates the observation in Superset's observations table.`, async ({ page }) => { // setup await openmrs.createPatient(); await openmrs.startPatientVisit(); @@ -275,7 +275,7 @@ test('Creating an OpenMRS obs creates the observation in Superset observations t await openmrs.voidPatient(); }); -test('Creating an OpenMRS appointment creates the appointment in Superset appointments table.', async ({ page }) => { +test(`Creating an OpenMRS appointment creates the appointment in Superset's appointments table.`, async ({ page }) => { // setup await openmrs.createPatient(); await openmrs.searchPatientId(); @@ -323,7 +323,7 @@ test('Creating an OpenMRS appointment creates the appointment in Superset appoin await openmrs.voidPatient(); }); -test('Voiding an OpenMRS obs updates the observation in Superset observations table.', async ({ page }) => { +test(`Voiding an OpenMRS obs updates the observation in Superset's observations table.`, async ({ page }) => { // setup await openmrs.createPatient(); await openmrs.startPatientVisit(); @@ -357,7 +357,7 @@ test('Voiding an OpenMRS obs updates the observation in Superset observations ta await openmrs.voidPatient(); }); -test('Voiding an OpenMRS patient updates the patient in Superset patients table.', async ({ page }) => { +test(`Voiding an OpenMRS patient updates the patient in Superset's patients table.`, async ({ page }) => { // setup await openmrs.createPatient(); await openmrs.searchPatientId(); @@ -382,7 +382,7 @@ test('Voiding an OpenMRS patient updates the patient in Superset patients table. await superset.clearSQLEditor(); }); -test('Voiding an OpenMRS condition updates the condition in Superset conditions table.', async ({ page }) => { +test(`Voiding an OpenMRS condition updates the condition in Superset's conditions table.`, async ({ page }) => { // setup await openmrs.createPatient(); await openmrs.searchPatientId(); @@ -418,7 +418,7 @@ test('Voiding an OpenMRS condition updates the condition in Superset conditions await openmrs.voidPatient(); }); -test('Voiding an OpenMRS encounter updates the encounter in Superset encounters table.', async ({ page }) => { +test(`Voiding an OpenMRS encounter updates the encounter in Superset's encounters table.`, async ({ page }) => { // setup await openmrs.createPatient(); await openmrs.searchPatientId(); @@ -457,7 +457,7 @@ test('Voiding an OpenMRS encounter updates the encounter in Superset encounters await openmrs.voidPatient(); }); -test('Cancelling an OpenMRS appointment updates the appointment in Superset appointments table.', async ({ page }) => { +test(`Cancelling an OpenMRS appointment updates the appointment in Superset's appointments table.`, async ({ page }) => { // setup await openmrs.createPatient(); await openmrs.searchPatientId(); diff --git a/e2e/utils/functions/odoo.ts b/e2e/utils/functions/odoo.ts index 7132f98..557fcb9 100644 --- a/e2e/utils/functions/odoo.ts +++ b/e2e/utils/functions/odoo.ts @@ -20,12 +20,44 @@ export class Odoo { await expect(this.page).toHaveURL(/.*web/); } + async createCustomer() { + await this.page.getByPlaceholder('Search...').type(`${patientName.firstName + ' ' + patientName.givenName}`); + await this.page.getByPlaceholder('Search...').press('Enter'); + await delay(2000); + } + async searchCustomer() { + await this.page.getByPlaceholder('Search...').type(`${patientName.firstName + ' ' + patientName.givenName}`); + await this.page.getByPlaceholder('Search...').press('Enter'); + await delay(2000); + } + + async navigateToSales() { await this.page.locator("//a[contains(@class, 'full')]").click(); await this.page.getByRole('menuitem', { name: 'Sales' }).click(); await expect(this.page.locator('.breadcrumb-item')).toHaveText('Quotations'); - await this.page.getByPlaceholder('Search...').type(`${patientName.firstName + ' ' + patientName.givenName}`); - await this.page.getByPlaceholder('Search...').press('Enter'); + } + + async createSaleOrderLine() { + await this.page.getByRole('button', { name: 'Create' }).click(); + await expect(this.page.locator('li.breadcrumb-item:nth-child(2)')).toHaveText(/new/i); + await this.page.getByLabel('Customer', { exact: true }).type(`${patientName.firstName + ' ' + patientName.givenName}`); + await this.page.getByText(`${patientName.firstName + ' ' + patientName.givenName}`).first().click(); + await this.page.getByRole('button', { name: 'Add a product' }).click(); + await this.page.locator('td.o_data_cell:nth-child(2) div:nth-child(1) input').fill('Acétaminophene Co 500mg'); + await this.page.getByText('Acétaminophene Co 500mg').first().click(); + await this.page.locator('input[name="product_uom_qty"]').clear(); + await this.page.locator('input[name="product_uom_qty"]').fill('8'); + await this.page.locator('td.o_data_cell:nth-child(7) input').clear(); + await this.page.locator('td.o_data_cell:nth-child(7) input').fill('2.00'); + await this.page.locator('td.o_data_cell:nth-child(9)').click(); await delay(2000); + await expect(this.page.locator('td.o_data_cell:nth-child(9)')).toHaveText('$ 16.00'); + await this.page.getByRole('button', { name: 'Confirm' }).click(); + await delay(3000); + await expect(this.page.locator('td.o_data_cell:nth-child(2) span:nth-child(1) span')).toHaveText('Acétaminophene Co 500mg'); + await expect(this.page.locator('td.o_data_cell:nth-child(4)')).toHaveText('8'); + await expect(this.page.locator('td.o_data_cell:nth-child(9)')).toHaveText('2.00'); + await expect(this.page.locator('td.o_data_cell:nth-child(11)')).toHaveText('$ 16.00'); } } diff --git a/e2e/utils/functions/openmrs.ts b/e2e/utils/functions/openmrs.ts index c848278..5ea56cc 100644 --- a/e2e/utils/functions/openmrs.ts +++ b/e2e/utils/functions/openmrs.ts @@ -150,6 +150,7 @@ export class OpenMRS { async voidPatient() { await this.page.goto(`${O3_URL}/openmrs/admin/patients/index.htm`); + await expect(await this.page.getByPlaceholder(' ')).toBeVisible(); await this.page.getByPlaceholder(' ').type(`${patientName.firstName + ' ' + patientName.givenName}`); await this.page.locator('#openmrsSearchTable tbody tr.odd td:nth-child(1)').click(); await this.page.locator('input[name="voidReason"]').fill('Void patient created by smoke test'); diff --git a/package.json b/package.json index 6e1444b..28afc93 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "!**/.git*/", "!*.gitignore", "!node_modules/", + "!tests/", "!test-results/", "!playwright-report/" ],