From c20cbf4be3153bb055cbd2ea80adc0c1f3fc52d1 Mon Sep 17 00:00:00 2001 From: Katarzyna Date: Tue, 27 Jan 2026 14:56:35 +0100 Subject: [PATCH 1/7] add new internal location to env --- .env.example | 1 + 1 file changed, 1 insertion(+) diff --git a/.env.example b/.env.example index 3f57985..e2aed1a 100644 --- a/.env.example +++ b/.env.example @@ -15,6 +15,7 @@ LOCATION_SUPPLIER_ALT=locationId LOCATION_DEPOT=locationId LOCATION_NO_PICK_AND_PUTAWAY_STOCK_DEPOT=locationId LOCATION_INTERNAL=locationId +LOCATION_INTERNAL_TWO=locationId LOCATION_WARD=locationId PRODUCT_ONE=productId PRODUCT_TWO=productId From a20f6d56d87844fa5b58e86dce586b014c187cb1 Mon Sep 17 00:00:00 2001 From: Katarzyna Date: Tue, 27 Jan 2026 14:57:12 +0100 Subject: [PATCH 2/7] add new internal location to playwright.yml --- .github/workflows/playwright.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index f1c9bb3..3cefd78 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -68,6 +68,7 @@ jobs: LOCATION_WARD: ${{ secrets.LOCATION_WARD }} LOCATION_NO_PICK_AND_PUTAWAY_STOCK_DEPOT: ${{ secrets.LOCATION_NO_PICK_AND_PUTAWAY_STOCK_DEPOT }} LOCATION_INTERNAL: ${{ secrets.LOCATION_INTERNAL }} + LOCATION_INTERNAL_TWO: ${{ secrets.LOCATION_INTERNAL_TWO }} PRODUCT_ONE: ${{ secrets.PRODUCT_ONE }} PRODUCT_TWO: ${{ secrets.PRODUCT_TWO }} PRODUCT_THREE: ${{ secrets.PRODUCT_THREE }} From 8dcea4dd53e9372f771e15dcd79ae7a7decb6b25 Mon Sep 17 00:00:00 2001 From: Katarzyna Date: Tue, 27 Jan 2026 14:57:49 +0100 Subject: [PATCH 3/7] add new internal location to AppConfig --- src/config/AppConfig.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/config/AppConfig.ts b/src/config/AppConfig.ts index 0789f9c..1f8caea 100644 --- a/src/config/AppConfig.ts +++ b/src/config/AppConfig.ts @@ -26,6 +26,7 @@ export enum LOCATION_KEY { WARD = 'ward', NO_PICK_AND_PUTAWAY_STOCK = 'noPickAndPutawayStockDepot', BIN_LOCATION = 'internalLocation', + BIN_LOCATION2 = 'internalLocation2', } export enum PRODUCT_KEY { @@ -270,6 +271,19 @@ class AppConfig { type: LocationTypeCode.BIN_LOCATION, parentLocation: env.get('LOCATION_MAIN').required().asString(), }), + + internalLocation2: new LocationConfig({ + id: env.get('LOCATION_INTERNAL_TWO').asString(), + key: LOCATION_KEY.BIN_LOCATION, + name: this.uniqueIdentifier.generateUniqueString('bin-location2'), + requiredActivityCodes: new Set([ + ActivityCode.PICK_STOCK, + ActivityCode.PUTAWAY_STOCK, + ]), + required: false, + type: LocationTypeCode.BIN_LOCATION, + parentLocation: env.get('LOCATION_MAIN').required().asString(), + }), }; this.products = { From a0f474fb47002d577dcc759505e76cad2c7755e3 Mon Sep 17 00:00:00 2001 From: Katarzyna Date: Tue, 27 Jan 2026 14:58:18 +0100 Subject: [PATCH 4/7] update fixtures with new location --- src/fixtures/fixtures.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fixtures/fixtures.ts b/src/fixtures/fixtures.ts index fa461e5..1d8e166 100644 --- a/src/fixtures/fixtures.ts +++ b/src/fixtures/fixtures.ts @@ -92,6 +92,8 @@ type Fixtures = { wardLocationService: LocationData; noPickAndPutawayStockDepotService: LocationData; internalLocationService: LocationData; + internalLocation2Service: LocationData; + // PRODUCT DATA mainProductService: ProductData; otherProductService: ProductData; @@ -179,6 +181,8 @@ export const test = baseTest.extend({ use(new LocationData(LOCATION_KEY.NO_PICK_AND_PUTAWAY_STOCK, page.request)), internalLocationService: async ({ page }, use) => use(new LocationData(LOCATION_KEY.BIN_LOCATION, page.request)), + internalLocation2Service: async ({ page }, use) => + use(new LocationData(LOCATION_KEY.BIN_LOCATION2, page.request)), // PRODUCTS mainProductService: async ({ page }, use) => use(new ProductData(PRODUCT_KEY.ONE, page.request)), From 76a7504087199321e5384148d41ccea5b50d8e2e Mon Sep 17 00:00:00 2001 From: Katarzyna Date: Tue, 27 Jan 2026 14:59:38 +0100 Subject: [PATCH 5/7] add elements to putaway pages --- src/pages/putaway/components/CompletePutawayTable.ts | 6 +++++- src/pages/putaway/components/SplitModalTable.ts | 8 ++++++++ src/pages/putaway/components/StartPutawayTable.ts | 4 ++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/pages/putaway/components/CompletePutawayTable.ts b/src/pages/putaway/components/CompletePutawayTable.ts index 5c0803b..fbb7d66 100644 --- a/src/pages/putaway/components/CompletePutawayTable.ts +++ b/src/pages/putaway/components/CompletePutawayTable.ts @@ -12,7 +12,7 @@ class CompletePutawayTable extends BasePageModel { } get rows() { - return this.table.getByRole('rowgroup'); + return this.table.getByRole('row'); } row(index: number) { @@ -27,6 +27,10 @@ class Row extends BasePageModel { super(page); this.row = row; } + + getputawayBin(rowIndex: number) { + return this.row.getByTestId(`cell-${rowIndex}-undefined`).nth(9); + } } export default CompletePutawayTable; diff --git a/src/pages/putaway/components/SplitModalTable.ts b/src/pages/putaway/components/SplitModalTable.ts index 71f4399..90fe399 100644 --- a/src/pages/putaway/components/SplitModalTable.ts +++ b/src/pages/putaway/components/SplitModalTable.ts @@ -47,6 +47,14 @@ class Row extends BasePageModel { get quantityField() { return this.row.getByRole('cell').getByTestId('quantity-input'); } + + get clearBinSelect() { + return this.row.locator('.react-select__clear-indicator'); + } + + get putawayBinField() { + return this.row.getByTestId('bin-select').getByRole('textbox'); + } } export default SplitModalTable; diff --git a/src/pages/putaway/components/StartPutawayTable.ts b/src/pages/putaway/components/StartPutawayTable.ts index 3681890..3f4acf7 100644 --- a/src/pages/putaway/components/StartPutawayTable.ts +++ b/src/pages/putaway/components/StartPutawayTable.ts @@ -62,6 +62,10 @@ class Row extends BasePageModel { get quantityField() { return this.row.getByTestId('cell-0-quantity').getByRole('spinbutton'); } + + get splitLineinPutawayBin() { + return this.row.getByTestId('cell-0-putawayBin'); + } } export default StartPutawayTable; From 614f177d39b20bc67bf26e6c1fe6ac30e2f3e738 Mon Sep 17 00:00:00 2001 From: Katarzyna Date: Tue, 27 Jan 2026 15:00:18 +0100 Subject: [PATCH 6/7] add test to assert split line in putaway --- src/tests/putaway/splitLineInPutaway.test.ts | 346 +++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 src/tests/putaway/splitLineInPutaway.test.ts diff --git a/src/tests/putaway/splitLineInPutaway.test.ts b/src/tests/putaway/splitLineInPutaway.test.ts new file mode 100644 index 0000000..8300ee3 --- /dev/null +++ b/src/tests/putaway/splitLineInPutaway.test.ts @@ -0,0 +1,346 @@ +import AppConfig from '@/config/AppConfig'; +import { ShipmentType } from '@/constants/ShipmentType'; +import { expect, test } from '@/fixtures/fixtures'; +import { StockMovementResponse } from '@/types'; +import { getShipmentId, getShipmentItemId } from '@/utils/shipmentUtils'; + +test.describe('Split line in Putaway', () => { + let STOCK_MOVEMENT: StockMovementResponse; + + test.beforeEach( + async ({ + supplierLocationService, + stockMovementService, + fifthProductService, + receivingService, + }) => { + const supplierLocation = await supplierLocationService.getLocation(); + STOCK_MOVEMENT = await stockMovementService.createInbound({ + originId: supplierLocation.id, + }); + + const product = await fifthProductService.getProduct(); + + await stockMovementService.addItemsToInboundStockMovement( + STOCK_MOVEMENT.id, + [{ productId: product.id, quantity: 10 }] + ); + + await stockMovementService.sendInboundStockMovement(STOCK_MOVEMENT.id, { + shipmentType: ShipmentType.AIR, + }); + + const { data: stockMovement } = + await stockMovementService.getStockMovement(STOCK_MOVEMENT.id); + const shipmentId = getShipmentId(stockMovement); + const { data: receipt } = await receivingService.getReceipt(shipmentId); + const receivingBin = + AppConfig.instance.receivingBinPrefix + STOCK_MOVEMENT.identifier; + + await receivingService.createReceivingBin(shipmentId, receipt); + + await receivingService.updateReceivingItems(shipmentId, [ + { + shipmentItemId: getShipmentItemId(receipt, 0, 0), + quantityReceiving: 10, + binLocationName: receivingBin, + }, + ]); + await receivingService.completeReceipt(shipmentId); + } + ); + + test.afterEach( + async ({ + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + }) => { + await navbar.configurationButton.click(); + await navbar.transactions.click(); + await transactionListPage.table.row(1).actionsButton.click(); + await transactionListPage.table.deleteButton.click(); + await expect(transactionListPage.successMessage).toBeVisible(); + await transactionListPage.table.row(1).actionsButton.click(); + await transactionListPage.table.deleteButton.click(); + await expect(transactionListPage.successMessage).toBeVisible(); + await transactionListPage.table.row(1).actionsButton.click(); + await transactionListPage.table.deleteButton.click(); + await expect(transactionListPage.successMessage).toBeVisible(); + + await stockMovementShowPage.goToPage(STOCK_MOVEMENT.id); + await stockMovementShowPage.detailsListTable.oldViewShipmentPage.click(); + await oldViewShipmentPage.undoStatusChangeButton.click(); + await stockMovementShowPage.isLoaded(); + await stockMovementShowPage.rollbackButton.click(); + + await stockMovementService.deleteStockMovement(STOCK_MOVEMENT.id); + } + ); + + test('Assert split line in Putaway', async ({ + stockMovementShowPage, + navbar, + createPutawayPage, + internalLocationService, + internalLocation2Service, + putawayDetailsPage, + productShowPage, + fifthProductService, + }) => { + const internalLocation = await internalLocationService.getLocation(); + const internalLocation2 = await internalLocation2Service.getLocation(); + const receivingBin = + AppConfig.instance.receivingBinPrefix + STOCK_MOVEMENT.identifier; + await test.step('Go to create putaway page', async () => { + await stockMovementShowPage.goToPage(STOCK_MOVEMENT.id); + await stockMovementShowPage.isLoaded(); + await navbar.profileButton.click(); + await navbar.refreshCachesButton.click(); + await navbar.inbound.click(); + await navbar.createPutaway.click(); + await createPutawayPage.isLoaded(); + }); + + await test.step('Start putaway', async () => { + await createPutawayPage.table.row(0).checkbox.click(); + await createPutawayPage.startPutawayButton.click(); + await createPutawayPage.startStep.isLoaded(); + }); + + await test.step('Split line in putaway', async () => { + await createPutawayPage.startStep.table.row(0).splitLineButton.click(); + await createPutawayPage.startStep.splitModal.isLoaded(); + await createPutawayPage.startStep.splitModal.addLineButton.click(); + await createPutawayPage.startStep.splitModal.table + .row(1) + .getPutawayBin(internalLocation.name); + await createPutawayPage.startStep.splitModal.table + .row(1) + .quantityField.fill('5'); + await createPutawayPage.startStep.splitModal.table + .row(2) + .getPutawayBin(internalLocation2.name); + await createPutawayPage.startStep.splitModal.table + .row(2) + .quantityField.fill('5'); + await createPutawayPage.startStep.splitModal.saveButton.click(); + }); + + await test.step('Assert split line on start step', async () => { + await expect( + createPutawayPage.startStep.table.row(0).splitLineinPutawayBin + ).toHaveText('Split line'); + }); + + await test.step('Go to next page and assert split line on complete step', async () => { + await createPutawayPage.startStep.nextButton.click(); + await createPutawayPage.completeStep.isLoaded(); + await expect( + createPutawayPage.completeStep.table.row(2).getputawayBin(0) + ).toContainText(internalLocation.name); + await expect( + createPutawayPage.completeStep.table.row(3).getputawayBin(1) + ).toContainText(internalLocation.name); + }); + + await test.step('Complete and assert completing putaway', async () => { + await createPutawayPage.completeStep.completePutawayButton.click(); + await putawayDetailsPage.isLoaded(); + await expect(putawayDetailsPage.statusTag).toHaveText('Completed'); + }); + + await test.step('Assert content of items status table', async () => { + await putawayDetailsPage.itemStatusTab.click(); + await expect( + putawayDetailsPage.itemStatusTable.row(1).itemStatus + ).toHaveText('COMPLETED'); + await expect( + putawayDetailsPage.itemStatusTable.row(1).originBin + ).toHaveText(receivingBin); + await expect( + putawayDetailsPage.itemStatusTable.row(1).destinationBin + ).toContainText(internalLocation.name); + await expect( + putawayDetailsPage.itemStatusTable.row(2).itemStatus + ).toHaveText('COMPLETED'); + await expect( + putawayDetailsPage.itemStatusTable.row(2).originBin + ).toHaveText(receivingBin); + await expect( + putawayDetailsPage.itemStatusTable.row(2).destinationBin + ).toContainText(internalLocation.name); + }); + + await test.step('Assert putaway bin on stock card', async () => { + await putawayDetailsPage.summaryTab.click(); + const product = await fifthProductService.getProduct(); + await productShowPage.goToPage(product.id); + await productShowPage.inStockTab.click(); + await productShowPage.inStockTabSection.isLoaded(); + await expect( + productShowPage.inStockTabSection.row(1).binLocation + ).toHaveText(internalLocation.name); + await expect( + productShowPage.inStockTabSection.row(2).binLocation + ).toHaveText(internalLocation2.name); + }); + }); + + test('Assert behavior when split into more than 1 line', async ({ + stockMovementShowPage, + navbar, + createPutawayPage, + internalLocationService, + internalLocation2Service, + putawayDetailsPage, + }) => { + const internalLocation = await internalLocationService.getLocation(); + const internalLocation2 = await internalLocation2Service.getLocation(); + await test.step('Go to create putaway page', async () => { + await stockMovementShowPage.goToPage(STOCK_MOVEMENT.id); + await stockMovementShowPage.isLoaded(); + await navbar.profileButton.click(); + await navbar.refreshCachesButton.click(); + await navbar.inbound.click(); + await navbar.createPutaway.click(); + await createPutawayPage.isLoaded(); + }); + + await test.step('Start putaway', async () => { + await createPutawayPage.table.row(0).checkbox.click(); + await createPutawayPage.startPutawayButton.click(); + await createPutawayPage.startStep.isLoaded(); + }); + + await test.step('Split line in putaway', async () => { + await createPutawayPage.startStep.table.row(0).splitLineButton.click(); + await createPutawayPage.startStep.splitModal.isLoaded(); + await createPutawayPage.startStep.splitModal.addLineButton.click(); + await createPutawayPage.startStep.splitModal.table + .row(1) + .getPutawayBin(internalLocation.name); + await createPutawayPage.startStep.splitModal.table + .row(1) + .quantityField.fill('5'); + await createPutawayPage.startStep.splitModal.table + .row(2) + .getPutawayBin(internalLocation2.name); + await createPutawayPage.startStep.splitModal.table + .row(2) + .quantityField.fill('5'); + await createPutawayPage.startStep.splitModal.saveButton.click(); + }); + + await test.step('Open split modal again and assert validation on empty bin', async () => { + await createPutawayPage.startStep.table.row(0).splitLineButton.click(); + await createPutawayPage.startStep.splitModal.isLoaded(); + await createPutawayPage.startStep.splitModal.table + .row(1) + .clearBinSelect.click(); + await createPutawayPage.startStep.splitModal.isLoaded(); + await createPutawayPage.startStep.splitModal.table + .row(1) + .putawayBinField.blur(); + await expect( + createPutawayPage.startStep.splitModal.table + .row(1) + .putawayBinField.first() + .locator('xpath=ancestor::td') + ).toHaveClass(/has-error/); + await expect( + createPutawayPage.startStep.splitModal.saveButton + ).toBeDisabled(); + }); + + await test.step('Edit putaway bin on split line modal', async () => { + await createPutawayPage.startStep.splitModal.table + .row(1) + .getPutawayBin(internalLocation2.name); + await expect( + createPutawayPage.startStep.splitModal.saveButton + ).toBeEnabled(); + await createPutawayPage.startStep.splitModal.saveButton.click(); + }); + + await test.step('Assert split line on start step', async () => { + await expect( + createPutawayPage.startStep.table.row(0).splitLineinPutawayBin + ).toHaveText('Split line'); + }); + + await test.step('Delete splitted line and add new line', async () => { + await createPutawayPage.startStep.table.row(0).splitLineButton.click(); + await createPutawayPage.startStep.splitModal.isLoaded(); + await createPutawayPage.startStep.splitModal.table + .row(1) + .deleteButton.click(); + await createPutawayPage.startStep.splitModal.addLineButton.click(); + await createPutawayPage.startStep.splitModal.table + .row(1) + .quantityField.fill('3'); + await createPutawayPage.startStep.splitModal.table + .row(2) + .getPutawayBin(internalLocation2.name); + await createPutawayPage.startStep.splitModal.table + .row(2) + .quantityField.fill('5'); + await createPutawayPage.startStep.splitModal.addLineButton.click(); + await createPutawayPage.startStep.splitModal.table + .row(3) + .quantityField.fill('2'); + await createPutawayPage.startStep.splitModal.table + .row(3) + .getPutawayBin(internalLocation2.name); + + await createPutawayPage.startStep.splitModal.saveButton.click(); + await expect( + createPutawayPage.startStep.table.row(0).splitLineinPutawayBin + ).toHaveText('Split line'); + }); + + await test.step('Go to next page and assert split line on complete step', async () => { + await createPutawayPage.startStep.nextButton.click(); + await createPutawayPage.completeStep.isLoaded(); + await expect( + createPutawayPage.completeStep.table.row(2).getputawayBin(0) + ).toContainText(internalLocation.name); + await expect( + createPutawayPage.completeStep.table.row(3).getputawayBin(1) + ).toContainText(internalLocation.name); + await expect( + createPutawayPage.completeStep.table.row(4).getputawayBin(2) + ).toContainText(internalLocation.name); + }); + + await test.step('Complete and assert completing putaway', async () => { + await createPutawayPage.completeStep.completePutawayButton.click(); + await putawayDetailsPage.isLoaded(); + await expect(putawayDetailsPage.statusTag).toHaveText('Completed'); + }); + + await test.step('Assert content of items status table', async () => { + await putawayDetailsPage.itemStatusTab.click(); + await expect( + putawayDetailsPage.itemStatusTable.row(1).itemStatus + ).toHaveText('COMPLETED'); + await expect( + putawayDetailsPage.itemStatusTable.row(1).destinationBin + ).toContainText(internalLocation2.name); + await expect( + putawayDetailsPage.itemStatusTable.row(2).itemStatus + ).toHaveText('COMPLETED'); + await expect( + putawayDetailsPage.itemStatusTable.row(2).destinationBin + ).toContainText(internalLocation2.name); + await expect( + putawayDetailsPage.itemStatusTable.row(3).itemStatus + ).toHaveText('COMPLETED'); + await expect( + putawayDetailsPage.itemStatusTable.row(3).destinationBin + ).toContainText(internalLocation2.name); + }); + }); +}); From 727302c027b8528f9f89dca4163d7d4adab8e2b1 Mon Sep 17 00:00:00 2001 From: Katarzyna Date: Wed, 28 Jan 2026 10:34:08 +0100 Subject: [PATCH 7/7] improve assertion --- src/tests/putaway/splitLineInPutaway.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/putaway/splitLineInPutaway.test.ts b/src/tests/putaway/splitLineInPutaway.test.ts index 8300ee3..44fa590 100644 --- a/src/tests/putaway/splitLineInPutaway.test.ts +++ b/src/tests/putaway/splitLineInPutaway.test.ts @@ -328,19 +328,19 @@ test.describe('Split line in Putaway', () => { ).toHaveText('COMPLETED'); await expect( putawayDetailsPage.itemStatusTable.row(1).destinationBin - ).toContainText(internalLocation2.name); + ).toContainText(internalLocation.name); await expect( putawayDetailsPage.itemStatusTable.row(2).itemStatus ).toHaveText('COMPLETED'); await expect( putawayDetailsPage.itemStatusTable.row(2).destinationBin - ).toContainText(internalLocation2.name); + ).toContainText(internalLocation.name); await expect( putawayDetailsPage.itemStatusTable.row(3).itemStatus ).toHaveText('COMPLETED'); await expect( putawayDetailsPage.itemStatusTable.row(3).destinationBin - ).toContainText(internalLocation2.name); + ).toContainText(internalLocation.name); }); }); });