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

OZ-711: Modifying the details of a sale order in Odoo should update the respective entry in Superset's sale_order_lines table. #122

Merged
merged 3 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions e2e/tests/keycloak-odoo-flows.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ test('Coded Odoo groups create corresponding Keycloak roles.', async ({ page })

test('Creating an Odoo group creates the corresponding Keycloak role', async ({ page }) => {
// setup
test.setTimeout(360000);
await page.goto(`${ODOO_URL}`);
await odoo.enterLoginCredentials();
await expect(page.locator('li.o_user_menu a span')).toHaveText(/administrator/i);
Expand All @@ -100,6 +101,7 @@ test('Creating an Odoo group creates the corresponding Keycloak role', async ({

test('Updating a synced Odoo group updates the corresponding Keycloak role.', async ({ page }) => {
// setup
test.setTimeout(720000);
await page.goto(`${ODOO_URL}`);
await odoo.enterLoginCredentials();
await expect(page.locator('li.o_user_menu a span')).toHaveText(/administrator/i);
Expand Down Expand Up @@ -131,6 +133,7 @@ test('Updating a synced Odoo group updates the corresponding Keycloak role.', as

test('Deleting a synced Odoo group deletes the corresponding Keycloak role.', async ({ page }) => {
// setup
test.setTimeout(720000);
await page.goto(`${ODOO_URL}`);
await odoo.enterLoginCredentials();
await expect(page.locator('li.o_user_menu a span')).toHaveText(/administrator/i);
Expand Down
3 changes: 3 additions & 0 deletions e2e/tests/keycloak-openmrs-flows.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ test('Logging out from OpenMRS ends the session in Keycloak and logs out the use

test('Creating an OpenMRS role creates the corresponding Keycloak role.', async ({ page }) => {
// setup
test.setTimeout(240000);
await page.goto(`${O3_URL}/openmrs/admin/users/role.list`);

// replay
Expand All @@ -62,6 +63,7 @@ test('Creating an OpenMRS role creates the corresponding Keycloak role.', async

test('Updating a synced OpenMRS role updates the corresponding Keycloak role.', async ({ page }) => {
// setup
test.setTimeout(420000);
await page.goto(`${O3_URL}/openmrs/admin/users/role.list`);
await openmrs.addRole();
await keycloak.open();
Expand Down Expand Up @@ -98,6 +100,7 @@ test('Updating a synced OpenMRS role updates the corresponding Keycloak role.',

test('Deleting a synced OpenMRS role deletes the corresponding Keycloak role.', async ({ page }) => {
// setup
test.setTimeout(420000);
await page.goto(`${O3_URL}/openmrs/admin/users/role.list`);
await openmrs.addRole();
await keycloak.open();
Expand Down
1 change: 0 additions & 1 deletion e2e/tests/keycloak-senaite-flows.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ test('Logging out from SENAITE ends the session in Keycloak and logs out the use

// replay
await senaite.logout();
await keycloak.confirmLogout();
await expect(page.locator('#username')).toBeVisible();

// verify
Expand Down
124 changes: 123 additions & 1 deletion e2e/tests/odoo-superset-flows.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { test, expect } from '@playwright/test';
import { O3_URL, SUPERSET_URL } from '../utils/configs/globalSetup';
import { O3_URL, ODOO_URL, SUPERSET_URL } from '../utils/configs/globalSetup';
import { Odoo } from '../utils/functions/odoo';
import { Superset } from '../utils/functions/superset';
import { OpenMRS, patientName } from '../utils/functions/openmrs';
Expand Down Expand Up @@ -62,6 +62,128 @@ test(`Creating an Odoo sale order line generates an entry in Superset's sale_ord
await expect(unitPrice).toBe(2);
});

test(`Revising an Odoo sale order line modifies the corresponding entry in Superset's sale_order_lines table.`, async ({ page }) => {
kdaud marked this conversation as resolved.
Show resolved Hide resolved
// setup
await openmrs.searchPatient(`${patientName.firstName + ' ' + patientName.givenName}`);
await openmrs.navigateToLabOrderForm();
await page.getByRole('searchbox').fill('Complete blood count');
await openmrs.saveLabOrder();
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');
await superset.open();
await superset.selectDBSchema();
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');
await expect(page.locator('div.virtual-table-cell:nth-child(4)')).toHaveText('8');
await expect(page.locator('div.virtual-table-cell:nth-child(5)')).toHaveText('2');

// replay
await page.goto(`${ODOO_URL}`);
await odoo.navigateToSales();
await odoo.searchCustomer();
await page.getByRole('cell', { name: `${patientName.firstName + ' ' + patientName.givenName}` }).nth(0).click();
await odoo.modifySaleOrderLine();

// verify
await page.goto(`${SUPERSET_URL}/sqllab`);
await superset.clearSQLEditor();
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');
await expect(page.locator('div.virtual-table-cell:nth-child(4)')).toHaveText('10');
await expect(page.locator('div.virtual-table-cell:nth-child(5)')).toHaveText('3');
});

test(`Voiding an Odoo sale order line updates the corresponding entry in Superset's sale_order_lines table.`, async ({ page }) => {
// setup
await openmrs.searchPatient(`${patientName.firstName + ' ' + patientName.givenName}`);
await openmrs.navigateToLabOrderForm();
await page.getByRole('searchbox').fill('Complete blood count');
await openmrs.saveLabOrder();
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');
await superset.open();
await superset.selectDBSchema();
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');
await expect(page.locator('div.virtual-table-cell:nth-child(4)')).toHaveText('8');
await expect(page.locator('div.virtual-table-cell:nth-child(5)')).toHaveText('2');

// replay
await page.goto(`${ODOO_URL}`);
await odoo.navigateToSales();
await odoo.searchCustomer();
await page.getByRole('cell', { name: `${patientName.firstName + ' ' + patientName.givenName}` }).nth(0).click();
await odoo.voidSaleOrderLine();

// verify
await page.goto(`${SUPERSET_URL}/sqllab`);
await superset.clearSQLEditor();
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');
await expect(page.locator('div.virtual-table-cell:nth-child(4)')).not.toHaveText('8');
await expect(page.locator('div.virtual-table-cell:nth-child(4)')).toHaveText('0');
});

test(`Deleting an Odoo quotation line removes the corresponding entry in Superset's sale_order_lines table.`, async ({ page }) => {
kdaud marked this conversation as resolved.
Show resolved Hide resolved
// setup
await openmrs.searchPatient(`${patientName.firstName + ' ' + patientName.givenName}`);
await openmrs.navigateToLabOrderForm();
await page.getByRole('searchbox').fill('Complete blood count');
await openmrs.saveLabOrder();
await odoo.open();
await odoo.navigateToSales();
await odoo.createQuotationLine();
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(/acyclovir Sirop 200mg/i);
await superset.open();
await superset.selectDBSchema();
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(/acyclovir Sirop 200mg/i);
await expect(page.locator('div.virtual-table-cell:nth-child(4)')).toHaveText('6');
await expect(page.locator('div.virtual-table-cell:nth-child(5)')).toHaveText('2');

// replay
await page.goto(`${ODOO_URL}`);
await odoo.navigateToSales();
await odoo.searchCustomer();
await page.getByRole('cell', { name: `${patientName.firstName + ' ' + patientName.givenName}` }).nth(0).click();
await odoo.deleteQuotationLine();

// verify
await page.goto(`${SUPERSET_URL}/sqllab`);
await superset.clearSQLEditor();
await page.getByRole('textbox').first().fill(saleOrderLinesQuery);
await superset.runSQLQuery();
await expect(page.locator('div.ant-alert-message')).toHaveText(/the query returned no data/i);
});

test(`A (synced) sale order line in Odoo generates an entry in Superset's sale_order_lines table.`, async ({ page }) => {
// setup
await superset.open();
Expand Down
2 changes: 1 addition & 1 deletion e2e/tests/openmrs-superset-flows.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ test(`Creating an OpenMRS visit creates the visit in Superset's visits table.`,
await expect(page.locator('div.virtual-table-cell:nth-child(3)')).toHaveText('Inpatient Ward');
await expect(page.locator('div.virtual-table-cell:nth-child(6)')).toHaveText('Facility Visit');
await expect(page.locator('div.virtual-table-cell:nth-child(8)')).toHaveText('M');
await expect(page.locator('div.virtual-table-cell:nth-child(10)')).toHaveText('true')
await expect(page.locator('div.virtual-table-cell:nth-child(2)')).toHaveText('false')
await page.getByRole('tab', { name: 'Query history' }).click();
await superset.clearSQLEditor();
await openmrs.voidPatient();
Expand Down
44 changes: 42 additions & 2 deletions e2e/utils/functions/odoo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class Odoo {
}

async createSaleOrderLine() {
await this.page.getByRole('button', { name: 'Create' }).click();
await this.page.getByRole('button', { name: /create/i }).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();
Expand All @@ -52,13 +52,53 @@ export class Odoo {
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(), 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(), delay(3000);
await this.page.getByRole('button', { name: /confirm/i }).click(), 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');
}

async createQuotationLine() {
await this.page.getByRole('button', { name: /create/i }).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('Acyclovir Sirop 200mg');
await this.page.getByText('Acyclovir Sirop 200mg').first().click();
await this.page.locator('input[name="product_uom_qty"]').fill('6');
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(), delay(2000);
await expect(this.page.locator('td.o_data_cell:nth-child(9)')).toHaveText('$ 12.00');
await this.page.getByRole('button', { name: /save/i }).click(), delay(3000);
await expect(this.page.locator('td.o_data_cell:nth-child(2) span:nth-child(1) span')).toHaveText('Acyclovir Sirop 200mg');
}

async modifySaleOrderLine() {
await this.page.getByRole('button', { name: /edit/i }).click();
await this.page.getByText(/acétaminophene co 500mg/i).nth(1).click();
await this.page.locator('input[name="product_uom_qty"]').fill('10');
await this.page.locator('input[name="price_unit"]').fill('3');
await this.page.locator('td.o_field_x2many_list_row_add').click(), delay(2000);
await expect(this.page.locator('td.o_data_cell:nth-child(11)')).toHaveText('$ 30.00');
await this.page.getByRole('button', { name: /save/i }).click(), delay(3000);
}

async voidSaleOrderLine() {
await this.page.getByRole('button', { name: /edit/i }).click();
await this.page.getByText(/acétaminophene co 500mg/i).nth(1).click();
await this.page.locator('input[name="product_uom_qty"]').fill('0');
await this.page.getByRole('button', { name: /save/i }).click(), delay(1000);
await this.page.getByRole('button', { name: 'Ok' }).click(), delay(3000);
}

async deleteQuotationLine() {
await this.page.getByRole('button', { name: /edit/i }).click();
await this.page.getByRole('cell', { name: /delete row/i }).click();
await this.page.getByRole('button', { name: /save/i }).click(), delay(3000);
}

async activateDeveloperMode() {
await this.navigateToSettings();
await expect(this.page.locator('#devel_tool a:nth-child(1)')).toBeVisible();
Expand Down
19 changes: 8 additions & 11 deletions e2e/utils/functions/openmrs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class OpenMRS {
await this.page.locator('#username').fill(`${process.env.OZONE_USERNAME}`);
await this.page.getByRole('button', { name: /continue/i }).click();
await this.page.locator('#password').fill(`${process.env.OZONE_PASSWORD}`);
await this.page.getByRole('button', { name: /sign in/ }).click();
await this.page.getByRole('button', { name: /sign in/i }).click();
}

async createPatient() {
Expand All @@ -68,10 +68,8 @@ export class OpenMRS {
await this.page.locator('div[aria-label="day, "]').fill('16');
await this.page.locator('div[aria-label="month, "]').fill('08');
await this.page.locator('div[aria-label="year, "]').fill('2002');
await this.page.getByRole('button', { name: /register patient/i }).click();
await this.createPatientButton().click();
await expect(this.page.getByText(/new patient created/i)).toBeVisible(), delay(3000);;
await this.page.getByRole('button', { name: 'Close', exact: true }).click();
}

async goToHomePage() {
Expand Down Expand Up @@ -178,7 +176,7 @@ export class OpenMRS {

async addPatientAppointment() {
await this.page.getByRole('link', { name: /appointments/i }).click();
await this.page.getByRole('button', { name: /add/i, exact: true }).click();
await this.page.getByRole('button', { name: 'Add', exact: true }).click();
await this.page.getByLabel(/select a service/i).selectOption('General Medicine service');
await this.page.getByLabel(/select an appointment type/i).selectOption('Scheduled');
await this.page.locator('#duration').fill('40');
Expand All @@ -202,8 +200,8 @@ export class OpenMRS {

async navigateToLabOrderForm() {
await this.page.getByLabel(/order basket/i).click(), delay(2000);
await expect(this.page.getByRole('button', { name: /add/i, exact: true }).nth(1)).toBeVisible();
await this.page.getByRole('button', { name: /add/i, exact: true }).nth(1).click();
await expect(this.page.getByRole('button', { name: 'Add', exact: true }).nth(1)).toBeVisible();
await this.page.getByRole('button', { name: 'Add', exact: true }).nth(1).click();
}

async saveLabOrder() {
Expand All @@ -227,8 +225,7 @@ export class OpenMRS {
await this.page.getByRole('button', { name: /options/i, exact: true }).click();
await this.page.getByRole('menuitem', { name: /delete this encounter/i }).click();
await this.page.getByRole('button', { name: /danger delete/i }).click();
await expect(this.page.getByText(/encounter deleted/i)).toBeVisible();
await expect(this.page.getByText(/encounter successfully deleted/i)).toBeVisible(), delay(5000);
await expect(this.page.getByText(/encounter deleted/i)).toBeVisible(), delay(5000);
}

async cancelLabOrder() {
Expand All @@ -248,8 +245,8 @@ export class OpenMRS {
async navigateToDrugOrderForm() {
await expect(this.page.getByLabel(/order basket/i)).toBeVisible();
await this.page.getByLabel(/order basket/i).click(), delay(2000);
await expect(this.page.getByRole('button', { name: /add/i, exact: true }).nth(0)).toBeVisible();
await this.page.getByRole('button', { name: /add/i, exact: true }).nth(0).click();
await expect(this.page.getByRole('button', { name: 'Add', exact: true }).nth(0)).toBeVisible();
await this.page.getByRole('button', { name: 'Add', exact: true }).nth(0).click();
}

async fillDrugOrderForm() {
Expand Down Expand Up @@ -278,7 +275,7 @@ export class OpenMRS {
async createDrugOrderWithFreeTextDosage() {
await expect(this.page.getByLabel(/order basket/i)).toBeVisible();
await this.page.getByLabel(/order basket/i).click(), delay(2000);
await expect(this.page.getByRole('button', { name: /add/i, exact: true }).nth(0)).toBeVisible();
await expect(this.page.getByRole('button', { name: 'Add', exact: true }).nth(0)).toBeVisible();
await this.page.getByRole('button', { name: 'Add', exact: true }).nth(0).click();
await this.page.getByRole('searchbox').fill('Aspirin 325mg');
await this.page.getByRole('button', { name: 'Order form' }).click();
Expand Down
2 changes: 1 addition & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ dotenv.config();

const config: PlaywrightTestConfig = {
testDir: './e2e/tests',
timeout: 10 * 60 * 1000,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: The Keycloak-Odoo streaming requires a longer timeout due to its configuration, so I reduced the global timeout to 3 minutes and set longer timeouts for the relevant test cases.

timeout: 3 * 60 * 1000,
expect: {
timeout: 40 * 1000,
},
Expand Down