From 604570229dcd4f8e4905d265fda25da1a66a7f72 Mon Sep 17 00:00:00 2001 From: Katarzyna Krawczyk <33342488+kkrawczyk123@users.noreply.github.com> Date: Tue, 28 Jan 2025 14:29:29 +0100 Subject: [PATCH] OBPIH-6695 Add test for edit bin location in the middle of receipt (#40) * OBPIH-6695 add bin location tab and dialog to create location page * OBPIH-6695 add locators to receiving table * OBPIH-6695 add in stock tab to product page * OBPIH-6695 add test for edit bin location in the middle of receipt * OBPIH-6695 fix import on create location page * OBPIH-6695 fix another import --- .../createLocation/CreateLocationPage.ts | 8 + .../components/AddBinLocationDialog.ts | 13 ++ .../tabs/BinLocationsTabSection.ts | 36 ++++ .../product/productShow/ProductShowPage.ts | 11 ++ .../productShow/tabs/InStockTabSection.ts | 44 +++++ .../receiving/components/ReceivingTable.ts | 11 ++ .../editBinLocationWhenReceive.test.ts | 162 ++++++++++++++++++ 7 files changed, 285 insertions(+) create mode 100644 src/pages/location/createLocation/components/AddBinLocationDialog.ts create mode 100644 src/pages/location/createLocation/tabs/BinLocationsTabSection.ts create mode 100644 src/pages/product/productShow/tabs/InStockTabSection.ts create mode 100644 src/tests/receiving/editBinLocationWhenReceive.test.ts diff --git a/src/pages/location/createLocation/CreateLocationPage.ts b/src/pages/location/createLocation/CreateLocationPage.ts index 1edfbe8..45ef1c7 100644 --- a/src/pages/location/createLocation/CreateLocationPage.ts +++ b/src/pages/location/createLocation/CreateLocationPage.ts @@ -4,10 +4,13 @@ import { expect } from '@/fixtures/fixtures'; import BasePageModel from '@/pages/BasePageModel'; import LocationConfigurationTabSection from '@/pages/location/createLocation/tabs/LocationConfigurationTabSection'; import LocationDetailsTabSection from '@/pages/location/createLocation/tabs/LocationDetailsTabSection'; +import BinLocationsTabSection from '@/pages/location/createLocation/tabs/BinLocationsTabSection'; + class CreateLocationPage extends BasePageModel { locationDetailsTabSection: LocationDetailsTabSection; locationConfigurationTabSection: LocationConfigurationTabSection; + binLocationTabSection: BinLocationsTabSection; constructor(page: Page) { super(page); @@ -15,6 +18,7 @@ class CreateLocationPage extends BasePageModel { this.locationConfigurationTabSection = new LocationConfigurationTabSection( page ); + this.binLocationTabSection = new BinLocationsTabSection(page); } async gotToPage() { @@ -29,6 +33,10 @@ class CreateLocationPage extends BasePageModel { return this.page.getByRole('link', { name: 'Configuration' }); } + get binLocationTab() { + return this.page.getByRole('link', { name: 'Bin Locations' }); + } + get actionButton() { return this.page.getByRole('button', { name: 'action' }); } diff --git a/src/pages/location/createLocation/components/AddBinLocationDialog.ts b/src/pages/location/createLocation/components/AddBinLocationDialog.ts new file mode 100644 index 0000000..3b93a65 --- /dev/null +++ b/src/pages/location/createLocation/components/AddBinLocationDialog.ts @@ -0,0 +1,13 @@ +import BasePageModel from '@/pages/BasePageModel'; + +class AddBinLocationDialog extends BasePageModel { + get binLocationNameField() { + return this.page.locator('#dlgAddBinLocation').locator('#name'); + } + + get saveButton() { + return this.page.getByRole('button', { name: 'Save' }); + } +} + +export default AddBinLocationDialog; diff --git a/src/pages/location/createLocation/tabs/BinLocationsTabSection.ts b/src/pages/location/createLocation/tabs/BinLocationsTabSection.ts new file mode 100644 index 0000000..6f88fba --- /dev/null +++ b/src/pages/location/createLocation/tabs/BinLocationsTabSection.ts @@ -0,0 +1,36 @@ +import BasePageModel from '@/pages/BasePageModel'; +import { expect, Page } from '@playwright/test'; +import AddBinLocationDialog from '@/pages/location/createLocation/components/AddBinLocationDialog'; + +class BinLocationsTabSection extends BasePageModel { + addBinLocationDialog: AddBinLocationDialog; + + constructor(page: Page) { + super(page); + this.addBinLocationDialog = new AddBinLocationDialog(page); + } + + get section() { + return this.page.getByRole('region', { name: 'Bin Locations' }); + } + + async isLoaded() { + await expect( + this.page.locator('.box').getByText('Bin Locations') + ).toBeVisible(); + } + + get addBinLocationButton() { + return this.page.getByRole('button', { name: 'Add Bin Location' }); + } + + get searchField() { + return this.page.getByRole('textbox', { name: 'Search:' }); + } + + get deleteBinButton() { + return this.page.getByRole('link', { name: 'Delete' }); + } +} + +export default BinLocationsTabSection; diff --git a/src/pages/product/productShow/ProductShowPage.ts b/src/pages/product/productShow/ProductShowPage.ts index fa2b13b..45e15de 100644 --- a/src/pages/product/productShow/ProductShowPage.ts +++ b/src/pages/product/productShow/ProductShowPage.ts @@ -2,13 +2,16 @@ import { Page } from '@playwright/test'; import BasePageModel from '@/pages/BasePageModel'; import RecordStockSection from '@/pages/product/productShow/sections/RecordStockSection'; +import InStockTabSection from './tabs/InStockTabSection'; class ProductShowPage extends BasePageModel { recordStock: RecordStockSection; + inStockTabSection: InStockTabSection; constructor(page: Page) { super(page); this.recordStock = new RecordStockSection(page); + this.inStockTabSection = new InStockTabSection(page); } async goToPage(id: string) { @@ -22,6 +25,14 @@ class ProductShowPage extends BasePageModel { get recordStockButton() { return this.page.getByRole('link', { name: 'Record stock' }); } + + get inStockTab() { + return this.page.getByRole('link', { name: 'In Stock' }); + } + + get stockHistoryTab() { + return this.page.getByRole('link', { name: 'Stock History' }); + } } export default ProductShowPage; diff --git a/src/pages/product/productShow/tabs/InStockTabSection.ts b/src/pages/product/productShow/tabs/InStockTabSection.ts new file mode 100644 index 0000000..1529cd6 --- /dev/null +++ b/src/pages/product/productShow/tabs/InStockTabSection.ts @@ -0,0 +1,44 @@ +import BasePageModel from '@/pages/BasePageModel'; +import { expect, Locator, Page } from '@playwright/test'; + +class InStockTabSection extends BasePageModel { + constructor(page: Page) { + super(page); + } + + async isLoaded() { + await expect( + this.page.getByRole('heading').getByText('Current stock') + ).toBeVisible(); + } + + get table() { + return this.page.locator('#ui-tabs-1').getByRole('table'); + } + + get rows() { + return this.table.getByRole('row'); + } + + row(index: number) { + return new Row(this.page, this.rows.nth(index)); + } +} + +class Row extends BasePageModel { + row: Locator; + constructor(page: Page, row: Locator) { + super(page); + this.row = row; + } + + get actionsButton() { + return this.row.locator('.action-menu').getByRole('button'); + } + + get binLocation() { + return this.row.locator('.line').getByRole('link'); + } +} + +export default InStockTabSection; diff --git a/src/pages/receiving/components/ReceivingTable.ts b/src/pages/receiving/components/ReceivingTable.ts index 27ea8d5..d3d1a3a 100644 --- a/src/pages/receiving/components/ReceivingTable.ts +++ b/src/pages/receiving/components/ReceivingTable.ts @@ -53,6 +53,17 @@ class Row extends BasePageModel { getItem(name: string) { return this.row.getByTestId('label-field').getByText(name); } + + get binLocationSelect() { + return this.row.getByRole('cell', { name: 'Bin Location' }); + } + + getBinLocation(binLocation: string) { + return this.page + .getByTestId('custom-select-dropdown-menu') + .getByRole('listitem') + .getByText(binLocation, { exact: true }); + } } export default ReceivingTable; diff --git a/src/tests/receiving/editBinLocationWhenReceive.test.ts b/src/tests/receiving/editBinLocationWhenReceive.test.ts new file mode 100644 index 0000000..16fe135 --- /dev/null +++ b/src/tests/receiving/editBinLocationWhenReceive.test.ts @@ -0,0 +1,162 @@ +import { ShipmentType } from '@/constants/ShipmentType'; +import { expect, test } from '@/fixtures/fixtures'; +import { StockMovementResponse } from '@/types'; +import { getToday } from '@/utils/DateUtils'; +import UniqueIdentifier from '@/utils/UniqueIdentifier'; + +test.describe('Edit Bin Location when receive inbound stock movement', () => { + let STOCK_MOVEMENT: StockMovementResponse; + const description = 'some description'; + const dateRequested = getToday(); + const uniqueIdentifier = new UniqueIdentifier(); + const binLocationName = uniqueIdentifier.generateUniqueString('bin'); + + test.beforeEach( + async ({ + supplierLocationService, + mainLocationService, + stockMovementService, + mainProductService, + otherProductService, + page, + locationListPage, + createLocationPage, + }) => { + const supplierLocation = await supplierLocationService.getLocation(); + const mainLocation = await mainLocationService.getLocation(); + const PRODUCT_ONE = await mainProductService.getProduct(); + const PRODUCT_TWO = await otherProductService.getProduct(); + + STOCK_MOVEMENT = await stockMovementService.createInbound({ + originId: supplierLocation.id, + description, + dateRequested, + }); + + await stockMovementService.addItemsToInboundStockMovement( + STOCK_MOVEMENT.id, + [ + { productId: PRODUCT_ONE.id, quantity: 20 }, + { productId: PRODUCT_TWO.id, quantity: 10 }, + ] + ); + + await stockMovementService.sendInboundStockMovement(STOCK_MOVEMENT.id, { + shipmentType: ShipmentType.AIR, + }); + + await test.step('Create bin location for location', async () => { + await page.goto('./location/list'); + await locationListPage.searchByLocationNameField.fill( + mainLocation.name + ); + await locationListPage.findButton.click(); + await expect( + locationListPage.getLocationEditButton(mainLocation.name) + ).toBeVisible(); + await locationListPage.getLocationEditButton(mainLocation.name).click(); + await createLocationPage.binLocationTab.click(); + await createLocationPage.binLocationTabSection.isLoaded(); + await createLocationPage.binLocationTabSection.addBinLocationButton.click(); + await createLocationPage.binLocationTabSection.addBinLocationDialog.binLocationNameField.fill( + binLocationName + ); + await createLocationPage.binLocationTabSection.addBinLocationDialog.saveButton.click(); + }); + } + ); + + test.afterEach( + async ({ + stockMovementShowPage, + stockMovementService, + page, + locationListPage, + mainLocationService, + createLocationPage, + }) => { + await stockMovementShowPage.goToPage(STOCK_MOVEMENT.id); + await stockMovementShowPage.rollbackLastReceiptButton.click(); + await stockMovementShowPage.rollbackButton.click(); + await stockMovementService.deleteStockMovement(STOCK_MOVEMENT.id); + + await test.step('Delete created bin location', async () => { + const mainLocation = await mainLocationService.getLocation(); + await page.goto('./location/list'); + await locationListPage.searchByLocationNameField.fill( + mainLocation.name + ); + await locationListPage.findButton.click(); + await expect( + locationListPage.getLocationEditButton(mainLocation.name) + ).toBeVisible(); + await locationListPage.getLocationEditButton(mainLocation.name).click(); + await createLocationPage.binLocationTab.click(); + await createLocationPage.binLocationTabSection.isLoaded(); + await createLocationPage.binLocationTabSection.searchField.fill( + binLocationName + ); + await createLocationPage.binLocationTabSection.searchField.press( + 'Enter' + ); + await createLocationPage.binLocationTabSection.isLoaded(); + await createLocationPage.binLocationTabSection.deleteBinButton.click(); + await createLocationPage.binLocationTabSection.isLoaded(); + }); + } + ); + + test('Edit Bin location when receive', async ({ + stockMovementShowPage, + receivingPage, + productShowPage, + }) => { + await test.step('Go to stock movement show page', async () => { + await stockMovementShowPage.goToPage(STOCK_MOVEMENT.id); + await stockMovementShowPage.isLoaded(); + }); + + await test.step('Go to shipment receiving page', async () => { + await stockMovementShowPage.receiveButton.click(); + await receivingPage.receivingStep.isLoaded(); + }); + + await test.step('Edit bin when receive item', async () => { + await receivingPage.receivingStep.isLoaded(); + await receivingPage.receivingStep.table.row(1).binLocationSelect.click(); + await receivingPage.receivingStep.table + .row(1) + .getBinLocation(binLocationName) + .click(); + await receivingPage.receivingStep.table + .row(1) + .receivingNowField.textbox.fill('10'); + }); + + await test.step('Go to check page', async () => { + await receivingPage.nextButton.click(); + await receivingPage.checkStep.isLoaded(); + }); + + await test.step('Finish receipt of item', async () => { + await receivingPage.checkStep.isLoaded(); + await receivingPage.checkStep.receiveShipmentButton.click(); + await stockMovementShowPage.isLoaded(); + }); + + await test.step('Assert edited bin on Packing list', async () => { + await expect( + stockMovementShowPage.packingListTable.row(1).binLocation + ).toHaveText(binLocationName); + }); + + await test.step('Go to product page and assert bin location', async () => { + await stockMovementShowPage.packingListTable.row(1).product.click(); + await productShowPage.inStockTab.click(); + await productShowPage.inStockTabSection.isLoaded(); + await expect( + productShowPage.inStockTabSection.row(2).binLocation + ).toHaveText(binLocationName); + }); + }); +});