From 13371fb528bdf80d59f22473eee001877c98d3ee Mon Sep 17 00:00:00 2001 From: Alan Nadolny Date: Tue, 3 Nov 2026 11:55:06 +0100 Subject: [PATCH 1/2] Fix cleanup --- src/tests/putaway/putawayToPreferredBin.test.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/tests/putaway/putawayToPreferredBin.test.ts b/src/tests/putaway/putawayToPreferredBin.test.ts index 5cec4c7..e7d0e7d 100644 --- a/src/tests/putaway/putawayToPreferredBin.test.ts +++ b/src/tests/putaway/putawayToPreferredBin.test.ts @@ -21,6 +21,9 @@ import { byNameAsc } from '@/utils/sortUtils'; test.describe('Putaway to preferred bin and default bin', () => { let STOCK_MOVEMENT: StockMovementResponse; let PUTAWAY_ORDER_IDS: string[] = []; + // every completed putaway line creates a Transfer Out + Transfer In pair, + // so each test sets how many transactions its putaway leaves behind + let PUTAWAY_TRANSACTIONS_COUNT = 0; let product: ProductResponse; let product2: ProductResponse; const downloadedFilePaths: string[] = []; @@ -36,6 +39,7 @@ test.describe('Putaway to preferred bin and default bin', () => { internalLocationService, }) => { PUTAWAY_ORDER_IDS = []; + PUTAWAY_TRANSACTIONS_COUNT = 0; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -116,7 +120,9 @@ test.describe('Putaway to preferred bin and default bin', () => { }); if (allPutawaysCompleted) { - await transactionService.deleteRecentTransactions(2); + await transactionService.deleteRecentTransactions( + PUTAWAY_TRANSACTIONS_COUNT + ); } await deleteShipment({ stockMovementService, STOCK_MOVEMENT }); @@ -178,6 +184,9 @@ test.describe('Putaway to preferred bin and default bin', () => { await createPutawayPage.table.row(1).checkbox.click(); await createPutawayPage.table.row(2).checkbox.click(); PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); + // 2 lines: product without preferred bin goes to the default (no) bin, + // product with preferred bin goes to it - 2 transfer pairs in total + PUTAWAY_TRANSACTIONS_COUNT = 4; await createPutawayPage.startStep.isLoaded(); }); @@ -304,6 +313,7 @@ test.describe('Putaway to preferred bin and default bin', () => { .click(); await createPutawayPage.table.row(2).checkbox.click(); PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); + PUTAWAY_TRANSACTIONS_COUNT = 2; await createPutawayPage.startStep.isLoaded(); }); From a8a999bebeb0eb6da7c4f994049c0e735ec8e90e Mon Sep 17 00:00:00 2001 From: Alan Nadolny Date: Tue, 3 Nov 2026 12:55:02 +0100 Subject: [PATCH 2/2] Test cleaning up transactions --- src/api/TransactionService.ts | 35 +++++++++++++++++++ src/constants/applicationUrls.ts | 2 ++ src/pages/receiving/steps/ReceivingStep.ts | 13 +++++++ .../putaway/putawayMoreThan1Item.test.ts | 16 ++++----- .../putaway/putawayToPreferredBin.test.ts | 18 +++------- src/tests/receiving/assertQtyInputs.test.ts | 2 +- src/utils/putawayUtils.ts | 30 ++++++++++------ 7 files changed, 83 insertions(+), 33 deletions(-) diff --git a/src/api/TransactionService.ts b/src/api/TransactionService.ts index 00b7dd6..8e7a7c1 100644 --- a/src/api/TransactionService.ts +++ b/src/api/TransactionService.ts @@ -45,6 +45,41 @@ class TransactionService extends BaseServiceModel { location — the API counterpart of deleting the top rows on the transaction list page one by one. */ + /** + Deletes every recent transaction that belongs to one of the given orders + (e.g. putaway numbers like "P-887NMH"). Completing a putaway creates a + Transfer Out + Transfer In pair per line, and how many pairs depends on + the putaway lines, so counting "the N newest" rows is fragile; the + transaction details page names its order, which lets us match exactly. + + Deleting one side of a local transfer can remove its pair as well, so a + transaction that no longer shows its order number is simply skipped. + */ + async deleteTransactionsForOrders( + orderNumbers: string[], + scanCount = 30 + ): Promise { + if (orderNumbers.length === 0) { + return; + } + const transactionIds = await this.getRecentTransactionIds(scanCount); + for (const transactionId of transactionIds) { + const response = await this.request.get( + INVENTORY_URL.showTransaction(transactionId) + ); + if (!response.ok()) { + continue; + } + const html = await response.text(); + const belongsToOrder = orderNumbers.some((orderNumber) => + new RegExp(`\\b${orderNumber}\\b`).test(html) + ); + if (belongsToOrder) { + await this.deleteTransaction(transactionId); + } + } + } + async deleteRecentTransactions(count: number): Promise { const transactionIds = await this.getRecentTransactionIds(count); if (transactionIds.length < count) { diff --git a/src/constants/applicationUrls.ts b/src/constants/applicationUrls.ts index c3a218d..8cf8639 100644 --- a/src/constants/applicationUrls.ts +++ b/src/constants/applicationUrls.ts @@ -35,6 +35,8 @@ const INVENTORY_URL = { base: './inventory', listTransactions: (params: { max: number }) => `${INVENTORY_URL.base}/listTransactions?max=${params.max}`, + showTransaction: (id: string) => + `${INVENTORY_URL.base}/showTransaction/${id}`, deleteTransaction: (id: string) => `${INVENTORY_URL.base}/deleteTransaction/${id}`, }; diff --git a/src/pages/receiving/steps/ReceivingStep.ts b/src/pages/receiving/steps/ReceivingStep.ts index ad0069c..d903c43 100644 --- a/src/pages/receiving/steps/ReceivingStep.ts +++ b/src/pages/receiving/steps/ReceivingStep.ts @@ -31,6 +31,19 @@ class ReceivingStep extends BasePageModel { await expect(this.table.table.getByText('Loading...')).toBeHidden({ timeout: 20_000, }); + + // eslint-disable-next-line playwright/no-networkidle + await this.page.waitForLoadState('networkidle'); + } + + async autofillQuantities() { + const autosaveResponse = this.page.waitForResponse( + (response) => + response.url().includes('/items/batch') && + response.request().method() === 'POST' + ); + await this.autofillQuantitiesButton.click(); + await autosaveResponse; } async waitForData() { diff --git a/src/tests/putaway/putawayMoreThan1Item.test.ts b/src/tests/putaway/putawayMoreThan1Item.test.ts index 6614895..5879801 100644 --- a/src/tests/putaway/putawayMoreThan1Item.test.ts +++ b/src/tests/putaway/putawayMoreThan1Item.test.ts @@ -85,15 +85,15 @@ test.describe('Create putaway for more than 1 item, separate putaways', () => { }, testInfo ) => { - const { allPutawaysCompleted } = await cleanupPendingPutaways({ + const { completedPutawayNumbers } = await cleanupPendingPutaways({ putawayService, putawayOrderIds: PUTAWAY_ORDER_IDS, testInfo, }); - if (allPutawaysCompleted) { - await transactionService.deleteRecentTransactions(3); - } + await transactionService.deleteTransactionsForOrders( + completedPutawayNumbers + ); await deleteShipment({ stockMovementService, STOCK_MOVEMENT }); const receivingBin = @@ -345,15 +345,15 @@ test.describe('Putaway 2 items in the same putaway', () => { }, testInfo ) => { - const { allPutawaysCompleted } = await cleanupPendingPutaways({ + const { completedPutawayNumbers } = await cleanupPendingPutaways({ putawayService, putawayOrderIds: PUTAWAY_ORDER_IDS, testInfo, }); - if (allPutawaysCompleted) { - await transactionService.deleteRecentTransactions(2); - } + await transactionService.deleteTransactionsForOrders( + completedPutawayNumbers + ); await stockMovementShowPage.goToPage(STOCK_MOVEMENT.id); await stockMovementShowPage.detailsListTable.oldViewShipmentPage.click(); await oldViewShipmentPage.undoStatusChangeButton.click(); diff --git a/src/tests/putaway/putawayToPreferredBin.test.ts b/src/tests/putaway/putawayToPreferredBin.test.ts index e7d0e7d..bc8103f 100644 --- a/src/tests/putaway/putawayToPreferredBin.test.ts +++ b/src/tests/putaway/putawayToPreferredBin.test.ts @@ -21,9 +21,6 @@ import { byNameAsc } from '@/utils/sortUtils'; test.describe('Putaway to preferred bin and default bin', () => { let STOCK_MOVEMENT: StockMovementResponse; let PUTAWAY_ORDER_IDS: string[] = []; - // every completed putaway line creates a Transfer Out + Transfer In pair, - // so each test sets how many transactions its putaway leaves behind - let PUTAWAY_TRANSACTIONS_COUNT = 0; let product: ProductResponse; let product2: ProductResponse; const downloadedFilePaths: string[] = []; @@ -39,7 +36,6 @@ test.describe('Putaway to preferred bin and default bin', () => { internalLocationService, }) => { PUTAWAY_ORDER_IDS = []; - PUTAWAY_TRANSACTIONS_COUNT = 0; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -113,17 +109,15 @@ test.describe('Putaway to preferred bin and default bin', () => { }, testInfo ) => { - const { allPutawaysCompleted } = await cleanupPendingPutaways({ + const { completedPutawayNumbers } = await cleanupPendingPutaways({ putawayService, putawayOrderIds: PUTAWAY_ORDER_IDS, testInfo, }); - if (allPutawaysCompleted) { - await transactionService.deleteRecentTransactions( - PUTAWAY_TRANSACTIONS_COUNT - ); - } + await transactionService.deleteTransactionsForOrders( + completedPutawayNumbers + ); await deleteShipment({ stockMovementService, STOCK_MOVEMENT }); const product2 = await productService.getProduct(Product.FOUR); @@ -184,9 +178,6 @@ test.describe('Putaway to preferred bin and default bin', () => { await createPutawayPage.table.row(1).checkbox.click(); await createPutawayPage.table.row(2).checkbox.click(); PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); - // 2 lines: product without preferred bin goes to the default (no) bin, - // product with preferred bin goes to it - 2 transfer pairs in total - PUTAWAY_TRANSACTIONS_COUNT = 4; await createPutawayPage.startStep.isLoaded(); }); @@ -313,7 +304,6 @@ test.describe('Putaway to preferred bin and default bin', () => { .click(); await createPutawayPage.table.row(2).checkbox.click(); PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); - PUTAWAY_TRANSACTIONS_COUNT = 2; await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/receiving/assertQtyInputs.test.ts b/src/tests/receiving/assertQtyInputs.test.ts index 2732130..afb409c 100644 --- a/src/tests/receiving/assertQtyInputs.test.ts +++ b/src/tests/receiving/assertQtyInputs.test.ts @@ -83,7 +83,7 @@ test.describe('Assert if quantity inputs remain when split lines', () => { }); await test.step('Autofill receiving quantity', async () => { - await receivingPage.receivingStep.autofillQuantitiesButton.click(); + await receivingPage.receivingStep.autofillQuantities(); await expect( receivingPage.receivingStep.table.row(1).receivingNowField.numberbox ).toHaveValue('50'); diff --git a/src/utils/putawayUtils.ts b/src/utils/putawayUtils.ts index a6e77cc..6a91a17 100644 --- a/src/utils/putawayUtils.ts +++ b/src/utils/putawayUtils.ts @@ -3,20 +3,23 @@ import { TestInfo } from '@playwright/test'; import PutawayService from '@/api/PutawayService'; /** - Deletes the putaway order if it is still in PENDING status. Returns true - when a pending putaway was deleted, false when there was nothing to delete - (the order was completed or no longer exists). + Deletes the putaway order if it is still in PENDING status. Returns whether + a pending putaway was deleted, and the putaway number of an order that was + not pending (completed), so its transactions can be cleaned up. */ async function deletePutawayOrderIfPending( putawayService: PutawayService, putawayOrderId: string -): Promise { +): Promise<{ wasPending: boolean; completedPutawayNumber: string | null }> { const putaway = await putawayService.getPutaway(putawayOrderId); if (putaway?.data?.putawayStatus !== 'PENDING') { - return false; + return { + wasPending: false, + completedPutawayNumber: putaway?.data?.putawayNumber ?? null, + }; } await putawayService.deletePutawayOrder(putawayOrderId); - return true; + return { wasPending: true, completedPutawayNumber: null }; } /** @@ -39,11 +42,15 @@ export async function cleanupPendingPutaways({ }) { testInfo.setTimeout(testInfo.timeout + 60_000); - const deletedPendingPutaways = []; + const deletedPendingPutaways: boolean[] = []; + const completedPutawayNumbers: string[] = []; for (const putawayOrderId of putawayOrderIds) { - deletedPendingPutaways.push( - await deletePutawayOrderIfPending(putawayService, putawayOrderId) - ); + const { wasPending, completedPutawayNumber } = + await deletePutawayOrderIfPending(putawayService, putawayOrderId); + deletedPendingPutaways.push(wasPending); + if (completedPutawayNumber) { + completedPutawayNumbers.push(completedPutawayNumber); + } } return { @@ -53,5 +60,8 @@ export async function cleanupPendingPutaways({ anyPutawayCompleted: deletedPendingPutaways.some( (wasPending) => !wasPending ), + // pass to transactionService.deleteTransactionsForOrders to remove the + // transfer transactions those completed putaways created + completedPutawayNumbers, }; }