From 56450b6b7491bb9133a656b07d8a25a704292b49 Mon Sep 17 00:00:00 2001 From: Katarzyna Date: Wed, 8 Jul 2026 08:49:37 +0200 Subject: [PATCH 1/6] add assertions on data in pdfs to existing tests --- .../putaway/components/StartPutawayTable.ts | 2 +- .../putaway/assertZonesInPutaways.test.ts | 143 +++++++- ...eateMoreThan1PutawayForTheSameItem.test.ts | 38 ++- src/tests/putaway/createPutaway.test.ts | 61 +++- .../putaway/putawayToPreferredBin.test.ts | 97 ++++++ src/utils/pdfUtils.ts | 307 +++++++++++++++++- 6 files changed, 632 insertions(+), 16 deletions(-) diff --git a/src/pages/putaway/components/StartPutawayTable.ts b/src/pages/putaway/components/StartPutawayTable.ts index 70acacf..42998f5 100644 --- a/src/pages/putaway/components/StartPutawayTable.ts +++ b/src/pages/putaway/components/StartPutawayTable.ts @@ -92,7 +92,7 @@ class Row extends BasePageModel { return this.row.getByTestId('table-cell').nth(8); } - get currentdBin() { + get currentBin() { return this.row.getByTestId('table-cell').nth(9); } diff --git a/src/tests/putaway/assertZonesInPutaways.test.ts b/src/tests/putaway/assertZonesInPutaways.test.ts index 1e9a49b..a454969 100644 --- a/src/tests/putaway/assertZonesInPutaways.test.ts +++ b/src/tests/putaway/assertZonesInPutaways.test.ts @@ -1,9 +1,13 @@ +import path from 'node:path'; + import AppConfig from '@/config/AppConfig'; -import { LOCATION_URL } from '@/constants/applicationUrls'; +import { LOCATION_URL, PUTAWAY_URL } from '@/constants/applicationUrls'; import { ShipmentType } from '@/constants/ShipmentType'; import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { ProductResponse, StockMovementResponse } from '@/types'; +import { deleteFile, writeBufferToFile } from '@/utils/FileIOUtils'; +import { extractPdfColumnValues } from '@/utils/pdfUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -19,6 +23,7 @@ test.describe('Assert zones on putaway pages', () => { let productB: ProductResponse; const uniqueIdentifier = new UniqueIdentifier(); const zoneLocationName = uniqueIdentifier.generateUniqueString('zone'); + const downloadedFilePaths: string[] = []; test.beforeEach( async ({ @@ -224,6 +229,10 @@ test.describe('Assert zones on putaway pages', () => { await createLocationPage.locationConfigurationTabSection.activeCheckbox.uncheck(); await createLocationPage.locationConfigurationTabSection.saveButton.click(); }); + + while (downloadedFilePaths.length) { + deleteFile(downloadedFilePaths.pop() as string); + } } ); @@ -233,6 +242,7 @@ test.describe('Assert zones on putaway pages', () => { createPutawayPage, internalLocationService, putawayDetailsPage, + page, }) => { const receivingBin = AppConfig.instance.receivingBinPrefix + STOCK_MOVEMENT.identifier; @@ -276,10 +286,35 @@ test.describe('Assert zones on putaway pages', () => { .row(1) .getPutawayBin(internalLocation.name) .click(); - await createPutawayPage.startStep.nextButton.click(); + }); + + await test.step('Generate putaway pdf and assert putaway bin column', async () => { + const pdfResponsePromise = page.waitForResponse( + (resp) => + PUTAWAY_URL.generatePdfPattern.test(resp.url()) && + resp.status() === 200 + ); + const downloadPromise = page.waitForEvent('download'); + await createPutawayPage.startStep.generatePutawayListButton.click(); + const [pdfResponse, download] = await Promise.all([ + pdfResponsePromise, + downloadPromise, + ]); + + const pdfFilePath = path.join( + AppConfig.LOCAL_FILES_DIR_PATH, + download.suggestedFilename() + ); + writeBufferToFile(pdfFilePath, await pdfResponse.body()); + downloadedFilePaths.push(pdfFilePath); + + expect(await extractPdfColumnValues(pdfFilePath, 'Putaway Bin')).toEqual([ + `${zoneLocationName}: ${internalLocation.name}`, + ]); }); await test.step('Assert zones on confirm page', async () => { + await createPutawayPage.startStep.nextButton.click(); await createPutawayPage.completeStep.isLoaded(); await expect( createPutawayPage.completeStep.table.row(2).putawayBin @@ -320,7 +355,7 @@ test.describe('Assert zones on putaway pages', () => { await test.step('Assert zones on start putaway page', async () => { await expect( - createPutawayPage.startStep.table.row(1).currentdBin + createPutawayPage.startStep.table.row(1).currentBin ).toContainText(`${zoneLocationName}: ${internalLocation.name}`); await createPutawayPage.startStep.table .row(1) @@ -358,39 +393,135 @@ test.describe('Assert zones on putaway pages', () => { .click(); }); + await test.step('Generate putaway pdf and assert bin columns', async () => { + const pdfResponsePromise = page.waitForResponse( + (resp) => + PUTAWAY_URL.generatePdfPattern.test(resp.url()) && + resp.status() === 200 + ); + const downloadPromise = page.waitForEvent('download'); + await createPutawayPage.startStep.generatePutawayListButton.click(); + const [pdfResponse, download] = await Promise.all([ + pdfResponsePromise, + downloadPromise, + ]); + + const pdfFilePath = path.join( + AppConfig.LOCAL_FILES_DIR_PATH, + download.suggestedFilename() + ); + writeBufferToFile(pdfFilePath, await pdfResponse.body()); + downloadedFilePaths.push(pdfFilePath); + + expect( + await extractPdfColumnValues(pdfFilePath, 'Preferred Bins') + ).toEqual(['', `${zoneLocationName}: ${internalLocation.name}`]); + expect( + await extractPdfColumnValues(pdfFilePath, 'Current Bins') + ).toEqual([`${zoneLocationName}: ${internalLocation.name}`, 'null']); + expect(await extractPdfColumnValues(pdfFilePath, 'Putaway Bin')).toEqual([ + `${zoneLocationName}: ${internalLocation.name}`, + `${zoneLocationName}: ${internalLocation.name}`, + ]); + }); + await test.step('Apply ordering by current bin', async () => { await createPutawayPage.startStep.sortButton.click(); await expect(createPutawayPage.startStep.sortButton).toContainText( 'Sort by current bins' ); await expect( - createPutawayPage.startStep.table.row(1).currentdBin + createPutawayPage.startStep.table.row(1).currentBin ).toContainText(`${zoneLocationName}: ${internalLocation.name}`); await expect( createPutawayPage.startStep.table.row(2).preferredBin ).toContainText(`${zoneLocationName}: ${internalLocation.name}`); }); + await test.step('Generate putaway pdf and assert bin columns after sorting by current bin', async () => { + const pdfResponsePromise = page.waitForResponse( + (resp) => + PUTAWAY_URL.generatePdfPattern.test(resp.url()) && + resp.status() === 200 + ); + const downloadPromise = page.waitForEvent('download'); + await createPutawayPage.startStep.generatePutawayListButton.click(); + const [pdfResponse, download] = await Promise.all([ + pdfResponsePromise, + downloadPromise, + ]); + + const pdfFilePath = path.join( + AppConfig.LOCAL_FILES_DIR_PATH, + download.suggestedFilename() + ); + writeBufferToFile(pdfFilePath, await pdfResponse.body()); + downloadedFilePaths.push(pdfFilePath); + + expect( + await extractPdfColumnValues(pdfFilePath, 'Preferred Bins') + ).toEqual(['', `${zoneLocationName}: ${internalLocation.name}`]); + expect( + await extractPdfColumnValues(pdfFilePath, 'Current Bins') + ).toEqual([`${zoneLocationName}: ${internalLocation.name}`, 'null']); + expect(await extractPdfColumnValues(pdfFilePath, 'Putaway Bin')).toEqual([ + `${zoneLocationName}: ${internalLocation.name}`, + `${zoneLocationName}: ${internalLocation.name}`, + ]); + }); + await test.step('Apply ordering by preferred bin', async () => { await createPutawayPage.startStep.sortButton.click(); await expect(createPutawayPage.startStep.sortButton).toContainText( 'Sort by preferred bin' ); await expect( - createPutawayPage.startStep.table.row(2).currentdBin + createPutawayPage.startStep.table.row(2).currentBin ).toContainText(`${zoneLocationName}: ${internalLocation.name}`); await expect( createPutawayPage.startStep.table.row(1).preferredBin ).toContainText(`${zoneLocationName}: ${internalLocation.name}`); }); + await test.step('Generate putaway pdf and assert bin columns after sorting by preferred bin', async () => { + const pdfResponsePromise = page.waitForResponse( + (resp) => + PUTAWAY_URL.generatePdfPattern.test(resp.url()) && + resp.status() === 200 + ); + const downloadPromise = page.waitForEvent('download'); + await createPutawayPage.startStep.generatePutawayListButton.click(); + const [pdfResponse, download] = await Promise.all([ + pdfResponsePromise, + downloadPromise, + ]); + + const pdfFilePath = path.join( + AppConfig.LOCAL_FILES_DIR_PATH, + download.suggestedFilename() + ); + writeBufferToFile(pdfFilePath, await pdfResponse.body()); + downloadedFilePaths.push(pdfFilePath); + + expect( + await extractPdfColumnValues(pdfFilePath, 'Preferred Bins') + ).toEqual([`${zoneLocationName}: ${internalLocation.name}`, '']); + expect( + await extractPdfColumnValues(pdfFilePath, 'Current Bins') + ).toEqual(['null', `${zoneLocationName}: ${internalLocation.name}`]); + expect(await extractPdfColumnValues(pdfFilePath, 'Putaway Bin')).toEqual([ + `${zoneLocationName}: ${internalLocation.name}`, + `${zoneLocationName}: ${internalLocation.name}`, + ]); + }); + await test.step('Return to original order', async () => { await createPutawayPage.startStep.sortButton.click(); await expect(createPutawayPage.startStep.sortButton).toContainText( 'Sort by current bins' ); await expect( - createPutawayPage.startStep.table.row(1).currentdBin + createPutawayPage.startStep.table.row(1).currentBin ).toContainText(`${zoneLocationName}: ${internalLocation.name}`); await expect( createPutawayPage.startStep.table.row(2).preferredBin diff --git a/src/tests/putaway/createMoreThan1PutawayForTheSameItem.test.ts b/src/tests/putaway/createMoreThan1PutawayForTheSameItem.test.ts index 5c12687..9850927 100644 --- a/src/tests/putaway/createMoreThan1PutawayForTheSameItem.test.ts +++ b/src/tests/putaway/createMoreThan1PutawayForTheSameItem.test.ts @@ -1,8 +1,13 @@ +import path from 'node:path'; + import AppConfig from '@/config/AppConfig'; +import { PUTAWAY_URL } from '@/constants/applicationUrls'; import { ShipmentType } from '@/constants/ShipmentType'; import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; +import { deleteFile, writeBufferToFile } from '@/utils/FileIOUtils'; +import { extractPdfColumnValues } from '@/utils/pdfUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -12,6 +17,7 @@ import { test.describe('Create more than 1 putaway from the same item', () => { let STOCK_MOVEMENT: StockMovementResponse; + const downloadedFilePaths: string[] = []; test.beforeEach( async ({ @@ -79,6 +85,10 @@ test.describe('Create more than 1 putaway from the same item', () => { stockMovementService, STOCK_MOVEMENT, }); + + while (downloadedFilePaths.length) { + deleteFile(downloadedFilePaths.pop() as string); + } } ); @@ -90,6 +100,7 @@ test.describe('Create more than 1 putaway from the same item', () => { productShowPage, putawayDetailsPage, productService, + page, }) => { const product = await productService.getProduct(Product.FIVE); const internalLocation = await internalLocationService.getLocation(); @@ -203,10 +214,35 @@ test.describe('Create more than 1 putaway from the same item', () => { .row(0) .getPutawayBin(internalLocation.name) .click(); - await createPutawayPage.startStep.nextButton.click(); + }); + + await test.step('Generate putaway pdf and assert current bins column', async () => { + const pdfResponsePromise = page.waitForResponse( + (resp) => + PUTAWAY_URL.generatePdfPattern.test(resp.url()) && + resp.status() === 200 + ); + const downloadPromise = page.waitForEvent('download'); + await createPutawayPage.startStep.generatePutawayListButton.click(); + const [pdfResponse, download] = await Promise.all([ + pdfResponsePromise, + downloadPromise, + ]); + + const pdfFilePath = path.join( + AppConfig.LOCAL_FILES_DIR_PATH, + download.suggestedFilename() + ); + writeBufferToFile(pdfFilePath, await pdfResponse.body()); + downloadedFilePaths.push(pdfFilePath); + + expect( + await extractPdfColumnValues(pdfFilePath, 'Current Bins') + ).toEqual([internalLocation.name]); }); await test.step('Complete putaway', async () => { + await createPutawayPage.startStep.nextButton.click(); await createPutawayPage.completeStep.isLoaded(); await createPutawayPage.completeStep.completePutawayButton.click(); }); diff --git a/src/tests/putaway/createPutaway.test.ts b/src/tests/putaway/createPutaway.test.ts index 97c1218..ab23dc7 100644 --- a/src/tests/putaway/createPutaway.test.ts +++ b/src/tests/putaway/createPutaway.test.ts @@ -1,8 +1,13 @@ +import path from 'node:path'; + import AppConfig from '@/config/AppConfig'; +import { PUTAWAY_URL } from '@/constants/applicationUrls'; import { ShipmentType } from '@/constants/ShipmentType'; import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; +import { deleteFile, writeBufferToFile } from '@/utils/FileIOUtils'; +import { extractPdfColumnValues } from '@/utils/pdfUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -12,6 +17,7 @@ import { test.describe('Putaway received inbound shipment', () => { let STOCK_MOVEMENT: StockMovementResponse; + const downloadedFilePaths: string[] = []; test.beforeEach( async ({ @@ -79,6 +85,10 @@ test.describe('Putaway received inbound shipment', () => { stockMovementService, STOCK_MOVEMENT, }); + + while (downloadedFilePaths.length) { + deleteFile(downloadedFilePaths.pop() as string); + } } ); @@ -90,7 +100,10 @@ test.describe('Putaway received inbound shipment', () => { productShowPage, putawayDetailsPage, productService, + page, }) => { + const internalLocation = await internalLocationService.getLocation(); + await test.step('Go to stock movement show page and assert received status', async () => { await stockMovementShowPage.goToPage(STOCK_MOVEMENT.id); await stockMovementShowPage.isLoaded(); @@ -113,16 +126,61 @@ test.describe('Putaway received inbound shipment', () => { }); await test.step('Select bin to putaway', async () => { - const internalLocation = await internalLocationService.getLocation(); await createPutawayPage.startStep.table.row(0).putawayBinSelect.click(); await createPutawayPage.startStep.table .row(0) .getPutawayBin(internalLocation.name) .click(); + }); + + const downloadPutawayListPdf = async () => { + const pdfResponsePromise = page.waitForResponse( + (resp) => + PUTAWAY_URL.generatePdfPattern.test(resp.url()) && + resp.status() === 200 + ); + const downloadPromise = page.waitForEvent('download'); + await createPutawayPage.startStep.generatePutawayListButton.click(); + const [pdfResponse, download] = await Promise.all([ + pdfResponsePromise, + downloadPromise, + ]); + + const fullFilePath = path.join( + AppConfig.LOCAL_FILES_DIR_PATH, + download.suggestedFilename() + ); + writeBufferToFile(fullFilePath, await pdfResponse.body()); + downloadedFilePaths.push(fullFilePath); + return fullFilePath; + }; + + await test.step('Generate putaway pdf', async () => { + const pdfFilePath = await downloadPutawayListPdf(); + expect(await extractPdfColumnValues(pdfFilePath, 'Putaway Bin')).toEqual([ + internalLocation.name, + ]); + }); + + await test.step('Go to next page', async () => { await createPutawayPage.startStep.nextButton.click(); + await createPutawayPage.completeStep.isLoaded(); + }); + + await test.step('Go back to start step', async () => { + await createPutawayPage.completeStep.editButton.click(); + await createPutawayPage.startStep.isLoaded(); + }); + + await test.step('Generate putaway pdf again', async () => { + const pdfFilePath = await downloadPutawayListPdf(); + expect(await extractPdfColumnValues(pdfFilePath, 'Putaway Bin')).toEqual([ + internalLocation.name, + ]); }); await test.step('Go to next page and complete putaway', async () => { + await createPutawayPage.startStep.nextButton.click(); await createPutawayPage.completeStep.isLoaded(); await createPutawayPage.completeStep.completePutawayButton.click(); }); @@ -138,7 +196,6 @@ test.describe('Putaway received inbound shipment', () => { await productShowPage.goToPage(product.id); await productShowPage.inStockTab.click(); await productShowPage.inStockTabSection.isLoaded(); - const internalLocation = await internalLocationService.getLocation(); await expect( productShowPage.inStockTabSection.row(1).binLocation ).toHaveText(internalLocation.name); diff --git a/src/tests/putaway/putawayToPreferredBin.test.ts b/src/tests/putaway/putawayToPreferredBin.test.ts index 557c8bb..1087d8d 100644 --- a/src/tests/putaway/putawayToPreferredBin.test.ts +++ b/src/tests/putaway/putawayToPreferredBin.test.ts @@ -1,8 +1,13 @@ +import path from 'node:path'; + import AppConfig from '@/config/AppConfig'; +import { PUTAWAY_URL } from '@/constants/applicationUrls'; import { ShipmentType } from '@/constants/ShipmentType'; import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { ProductResponse, StockMovementResponse } from '@/types'; +import { deleteFile, writeBufferToFile } from '@/utils/FileIOUtils'; +import { extractPdfColumnValues } from '@/utils/pdfUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -15,6 +20,7 @@ test.describe('Putaway to preferred bin and default bin', () => { let STOCK_MOVEMENT: StockMovementResponse; let product: ProductResponse; let product2: ProductResponse; + const downloadedFilePaths: string[] = []; test.beforeEach( async ({ @@ -117,6 +123,10 @@ test.describe('Putaway to preferred bin and default bin', () => { productEditPage.inventoryLevelsTabSection.table ).toBeVisible(); await productEditPage.inventoryLevelsTabSection.createStockLevelModal.clickDeleteInventoryLevel(); + + while (downloadedFilePaths.length) { + deleteFile(downloadedFilePaths.pop() as string); + } } ); @@ -127,6 +137,7 @@ test.describe('Putaway to preferred bin and default bin', () => { internalLocationService, productShowPage, putawayDetailsPage, + page, }) => { const receivingBin = AppConfig.instance.receivingBinPrefix + STOCK_MOVEMENT.identifier; @@ -169,6 +180,35 @@ test.describe('Putaway to preferred bin and default bin', () => { ).toContainText(internalLocation.name); }); + await test.step('Generate putaway pdf and assert bin columns', async () => { + const pdfResponsePromise = page.waitForResponse( + (resp) => + PUTAWAY_URL.generatePdfPattern.test(resp.url()) && + resp.status() === 200 + ); + const downloadPromise = page.waitForEvent('download'); + await createPutawayPage.startStep.generatePutawayListButton.click(); + const [pdfResponse, download] = await Promise.all([ + pdfResponsePromise, + downloadPromise, + ]); + + const pdfFilePath = path.join( + AppConfig.LOCAL_FILES_DIR_PATH, + download.suggestedFilename() + ); + writeBufferToFile(pdfFilePath, await pdfResponse.body()); + downloadedFilePaths.push(pdfFilePath); + + expect( + await extractPdfColumnValues(pdfFilePath, 'Preferred Bins') + ).toEqual(['', internalLocation.name]); + expect(await extractPdfColumnValues(pdfFilePath, 'Putaway Bin')).toEqual([ + '', + internalLocation.name, + ]); + }); + await test.step('Assert confirm complete putaway dialog when empty putaway bin', async () => { await createPutawayPage.startStep.nextButton.click(); await createPutawayPage.completeStep.isLoaded(); @@ -222,6 +262,7 @@ test.describe('Putaway to preferred bin and default bin', () => { internalLocation2Service, productShowPage, putawayDetailsPage, + page, }) => { const receivingBin = AppConfig.instance.receivingBinPrefix + STOCK_MOVEMENT.identifier; @@ -259,6 +300,34 @@ test.describe('Putaway to preferred bin and default bin', () => { ).toContainText(internalLocation.name); }); + await test.step('Generate putaway pdf and assert bin columns', async () => { + const pdfResponsePromise = page.waitForResponse( + (resp) => + PUTAWAY_URL.generatePdfPattern.test(resp.url()) && + resp.status() === 200 + ); + const downloadPromise = page.waitForEvent('download'); + await createPutawayPage.startStep.generatePutawayListButton.click(); + const [pdfResponse, download] = await Promise.all([ + pdfResponsePromise, + downloadPromise, + ]); + + const pdfFilePath = path.join( + AppConfig.LOCAL_FILES_DIR_PATH, + download.suggestedFilename() + ); + writeBufferToFile(pdfFilePath, await pdfResponse.body()); + downloadedFilePaths.push(pdfFilePath); + + expect( + await extractPdfColumnValues(pdfFilePath, 'Preferred Bins') + ).toEqual([internalLocation.name]); + expect(await extractPdfColumnValues(pdfFilePath, 'Putaway Bin')).toEqual([ + internalLocation.name, + ]); + }); + await test.step('Edit putaway bin', async () => { await createPutawayPage.startStep.table.row(1).putawayBinSelect.click(); await createPutawayPage.startStep.table @@ -267,6 +336,34 @@ test.describe('Putaway to preferred bin and default bin', () => { .click(); }); + await test.step('Generate putaway pdf again and assert edited putaway bin', async () => { + const pdfResponsePromise = page.waitForResponse( + (resp) => + PUTAWAY_URL.generatePdfPattern.test(resp.url()) && + resp.status() === 200 + ); + const downloadPromise = page.waitForEvent('download'); + await createPutawayPage.startStep.generatePutawayListButton.click(); + const [pdfResponse, download] = await Promise.all([ + pdfResponsePromise, + downloadPromise, + ]); + + const pdfFilePath = path.join( + AppConfig.LOCAL_FILES_DIR_PATH, + download.suggestedFilename() + ); + writeBufferToFile(pdfFilePath, await pdfResponse.body()); + downloadedFilePaths.push(pdfFilePath); + + expect( + await extractPdfColumnValues(pdfFilePath, 'Preferred Bins') + ).toEqual([internalLocation.name]); + expect(await extractPdfColumnValues(pdfFilePath, 'Putaway Bin')).toEqual([ + internalLocation2.name, + ]); + }); + await test.step('Go to next page and assert edited putaway bin', async () => { await createPutawayPage.startStep.nextButton.click(); await createPutawayPage.completeStep.isLoaded(); diff --git a/src/utils/pdfUtils.ts b/src/utils/pdfUtils.ts index 5a7a251..b62eafa 100644 --- a/src/utils/pdfUtils.ts +++ b/src/utils/pdfUtils.ts @@ -1,7 +1,305 @@ import fs from 'node:fs'; import { getDocument } from 'pdfjs-dist/legacy/build/pdf.js'; -import type { TextItem } from 'pdfjs-dist/types/src/display/api'; +import type { + PDFDocumentProxy, + PDFPageProxy, + TextItem, +} from 'pdfjs-dist/types/src/display/api'; + +type PositionedTextItem = { + str: string; + x: number; + y: number; +}; + +type PdfTextLine = { + y: number; + items: PositionedTextItem[]; +}; + +type ColumnBounds = { + startX: number; + endX: number; +}; + +type ColumnHeader = { + y: number; + bounds: ColumnBounds; +}; + +const Y_TOLERANCE = 2; +const X_TOLERANCE = 2; +/** + Max vertical distance (in pdf units) between text lines belonging to the + same table header row. Header cells are vertically centered, so a header + row with wrapped labels renders up to three text lines a few units apart, + while the first data row starts further below (cell padding + borders). +*/ +const HEADER_BLOCK_SPAN = 12; +/** + Max vertical distance between consecutive table row lines. A bigger gap + means the table has ended and following text (e.g. a signature section or + page footer) is not part of it. +*/ +const MAX_ROW_GAP = 25; +/** + Max vertical distance between text lines belonging to the same table row. + A cell with wrapped content renders continuation lines one text line + (~10 units) below, while the next table row starts further down + (cell padding + borders). +*/ +const MAX_CELL_LINE_GAP = 12; + +const loadPdfDocument = (filePath: string): Promise => { + const data = new Uint8Array(fs.readFileSync(filePath)); + return getDocument({ data }).promise; +}; + +const getPageNumbers = (doc: PDFDocumentProxy): number[] => + Array.from({ length: doc.numPages }, (_, i) => i + 1); + +const getPositionedTextItems = async ( + page: PDFPageProxy +): Promise => { + const content = await page.getTextContent(); + return ( + content.items + // getTextContent() returns TextItem | TextMarkedContent; only TextItem + // carries actual text (`str`), so this type guard drops marked-content + // markers and narrows the type for the mapping below + .filter((item): item is TextItem => 'str' in item) + .filter((item) => item.str.trim()) + .map((item) => ({ + str: item.str.trim(), + x: item.transform[4], + y: item.transform[5], + })) + ); +}; + +const groupItemsIntoLines = (items: PositionedTextItem[]): PdfTextLine[] => + [...items] + .sort((a, b) => b.y - a.y) + .reduce((lines, item) => { + const line = lines.find((l) => Math.abs(l.y - item.y) <= Y_TOLERANCE); + if (!line) { + return [...lines, { y: item.y, items: [item] }]; + } + line.items.push(item); + return lines; + }, []) + .map((line) => ({ + ...line, + items: [...line.items].sort((a, b) => a.x - b.x), + })); + +type HeaderMatch = { + startX: number; + topY: number; + bottomY: number; + matchedItems: Set; +}; + +/** + Tries to match the full header text starting from the given item. + A wrapped header label continues on following text lines of the header + block, with each continuation fragment left-aligned with the first one. +*/ +const matchHeaderFromItem = ( + lines: PdfTextLine[], + lineIndex: number, + itemIndex: number, + columnHeader: string +): HeaderMatch | null => { + const startX = lines[lineIndex].items[itemIndex].x; + const matchedItems = new Set(); + let text = ''; + let bottomY = lines[lineIndex].y; + + const consumeLineItems = (line: PdfTextLine, fromIndex: number) => { + for (let i = fromIndex; i < line.items.length; i++) { + const candidate = text + ? `${text} ${line.items[i].str}` + : line.items[i].str; + if (!columnHeader.startsWith(candidate)) { + return; + } + text = candidate; + matchedItems.add(line.items[i]); + bottomY = line.y; + } + }; + + consumeLineItems(lines[lineIndex], itemIndex); + + for (let i = lineIndex + 1; i < lines.length; i++) { + if (text === columnHeader || lines[i].y < bottomY - HEADER_BLOCK_SPAN) { + break; + } + const alignedItemIndex = lines[i].items.findIndex( + (item) => Math.abs(item.x - startX) <= X_TOLERANCE + ); + if (alignedItemIndex === -1) { + continue; + } + consumeLineItems(lines[i], alignedItemIndex); + } + + if (text !== columnHeader) { + return null; + } + return { startX, topY: lines[lineIndex].y, bottomY, matchedItems }; +}; + +const getHeaderBlockLines = ( + lines: PdfTextLine[], + match: HeaderMatch +): PdfTextLine[] => + lines + .filter((line) => line.y <= match.topY + HEADER_BLOCK_SPAN) + .filter((line) => line.y >= match.bottomY - HEADER_BLOCK_SPAN); + +/** + The column ends where the closest other text of the header block starts, + i.e. at the smallest x (greater than the column start) among header block + items not belonging to the matched header itself. +*/ +const findColumnEndX = ( + headerBlockLines: PdfTextLine[], + match: HeaderMatch +): number => + headerBlockLines + .reduce((items, line) => items.concat(line.items), []) + .filter((item) => !match.matchedItems.has(item)) + .filter((item) => item.x > match.startX + X_TOLERANCE) + .reduce((endX, item) => Math.min(endX, item.x), Infinity); + +const findColumnHeader = ( + lines: PdfTextLine[], + columnHeader: string +): ColumnHeader | null => { + for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) { + for ( + let itemIndex = 0; + itemIndex < lines[lineIndex].items.length; + itemIndex++ + ) { + const match = matchHeaderFromItem( + lines, + lineIndex, + itemIndex, + columnHeader + ); + if (!match) { + continue; + } + const headerBlockLines = getHeaderBlockLines(lines, match); + return { + y: Math.min(...headerBlockLines.map((line) => line.y)), + bounds: { + startX: match.startX, + endX: findColumnEndX(headerBlockLines, match), + }, + }; + } + } + return null; +}; + +/** + Collects the lines making up the table body: lines below the header row, + until the first vertical gap bigger than a table row. +*/ +const getTableRowLines = ( + lines: PdfTextLine[], + headerBottomY: number +): PdfTextLine[] => { + const rowLines: PdfTextLine[] = []; + let previousY = headerBottomY; + + for (const line of lines) { + if (line.y >= headerBottomY - Y_TOLERANCE) { + continue; + } + if (previousY - line.y > MAX_ROW_GAP) { + break; + } + rowLines.push(line); + previousY = line.y; + } + + return rowLines; +}; + +const getCellValue = ( + line: PdfTextLine, + { startX, endX }: ColumnBounds +): string => + line.items + .filter((item) => item.x >= startX - X_TOLERANCE) + .filter((item) => item.x < endX - X_TOLERANCE) + .map((item) => item.str) + .join(' '); + +/** + Groups consecutive table body lines into rows: a line close enough to the + previous one is a continuation of the same row (wrapped cell content). +*/ +const groupLinesIntoRows = (rowLines: PdfTextLine[]): PdfTextLine[][] => + rowLines.reduce((rows, line) => { + const currentRow = rows[rows.length - 1]; + const previousLine = currentRow?.[currentRow.length - 1]; + if (previousLine && previousLine.y - line.y <= MAX_CELL_LINE_GAP) { + currentRow.push(line); + return rows; + } + return [...rows, [line]]; + }, []); + +const extractColumnValuesFromLines = ( + lines: PdfTextLine[], + columnHeader: string +): string[] => { + const header = findColumnHeader(lines, columnHeader); + if (!header) { + return []; + } + return groupLinesIntoRows(getTableRowLines(lines, header.y)).map((rowLines) => + rowLines + .map((line) => getCellValue(line, header.bounds)) + .filter(Boolean) + .join(' ') + ); +}; + +/** + Extracts cell values of a single table column from a PDF, identified by + its column header (wrapped, multi-line header labels are supported). + Column boundaries are derived from x coordinates of the header text, so + only values positioned within that column are returned — one entry per + table row (per page), with an empty string for an empty cell. A cell + wrapped into multiple text lines is joined back with spaces. +*/ +export const extractPdfColumnValues = async ( + filePath: string, + columnHeader: string +): Promise => { + const doc = await loadPdfDocument(filePath); + + const pageValues = await Promise.all( + getPageNumbers(doc).map(async (pageNum) => { + const page = await doc.getPage(pageNum); + const items = await getPositionedTextItems(page); + return extractColumnValuesFromLines( + groupItemsIntoLines(items), + columnHeader + ); + }) + ); + + return pageValues.reduce((all, values) => all.concat(values), []); +}; export const pdfContainsValues = async ( filePath: string, @@ -12,14 +310,11 @@ export const pdfContainsValues = async ( }; export const extractPdfText = async (filePath: string): Promise => { - const data = new Uint8Array(fs.readFileSync(filePath)); - const doc = await getDocument({ data }).promise; + const doc = await loadPdfDocument(filePath); - // Get page numbers available in the PDF - const pageNumbers = Array.from({ length: doc.numPages }, (_, i) => i + 1); // Extract text from each page const pageTexts = await Promise.all( - pageNumbers.map(async (pageNum) => { + getPageNumbers(doc).map(async (pageNum) => { const page = await doc.getPage(pageNum); const content = await page.getTextContent(); return content.items From f6ad05f84a4e9ad05797dac3350be0abf76769a7 Mon Sep 17 00:00:00 2001 From: Katarzyna Date: Fri, 10 Jul 2026 10:56:18 +0200 Subject: [PATCH 2/6] remove comment --- src/api/StockMovementService.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/api/StockMovementService.ts b/src/api/StockMovementService.ts index 3df67eb..951be94 100644 --- a/src/api/StockMovementService.ts +++ b/src/api/StockMovementService.ts @@ -68,8 +68,6 @@ class StockMovementService extends BaseServiceModel { } async deleteStockMovement(id: string) { - // request.delete does not throw on HTTP error statuses, and a swallowed - // failed delete leaves the stock movement behind for the next tests const apiResponse = await this.request.delete(STOCK_MOVEMENT_BY_ID(id)); if (!apiResponse.ok()) { throw new Error( From 8e8751fff4691ae618439d62e2ec51e4bc707e07 Mon Sep 17 00:00:00 2001 From: Katarzyna Date: Fri, 10 Jul 2026 10:56:47 +0200 Subject: [PATCH 3/6] increase timeout --- .github/workflows/playwright.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index c236bf9..6887076 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -30,7 +30,7 @@ concurrency: jobs: test: - timeout-minutes: 60 + timeout-minutes: 90 runs-on: ubuntu-latest permissions: id-token: write From a35e70228dda0f6d617e39c6b27a26c6519c6a62 Mon Sep 17 00:00:00 2001 From: Katarzyna Date: Fri, 10 Jul 2026 10:59:05 +0200 Subject: [PATCH 4/6] add removing pending putaway through api --- src/api/PutawayService.ts | 37 +++++++++++++++- src/constants/apiUrls.ts | 6 +++ src/pages/putaway/CreatePutawayPage.ts | 16 +++++++ src/types.d.ts | 7 +++ src/utils/putawayUtils.ts | 59 ++++++++++++++++++++++++++ 5 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 src/utils/putawayUtils.ts diff --git a/src/api/PutawayService.ts b/src/api/PutawayService.ts index 4e617a1..d3225cc 100644 --- a/src/api/PutawayService.ts +++ b/src/api/PutawayService.ts @@ -1,8 +1,12 @@ import { APIRequestContext } from '@playwright/test'; import BaseServiceModel from '@/api/BaseServiceModel'; -import { PUTAWAY_API } from '@/constants/apiUrls'; -import { ApiResponse, PutawayCandidate } from '@/types'; +import { + PUTAWAY_API, + PUTAWAY_BY_ID, + STOCK_TRANSFER_BY_ID, +} from '@/constants/apiUrls'; +import { ApiResponse, PutawayCandidate, PutawayResponse } from '@/types'; import { parseRequestToJSON } from '@/utils/ServiceUtils'; class PutawayService extends BaseServiceModel { @@ -24,6 +28,35 @@ class PutawayService extends BaseServiceModel { ); } } + + /** + Returns null when the putaway order does not exist (anymore). + */ + async getPutaway( + orderId: string + ): Promise | null> { + const apiResponse = await this.request.get(PUTAWAY_BY_ID(orderId)); + if (!apiResponse.ok()) { + return null; + } + return await parseRequestToJSON(apiResponse); + } + + /** + Putaway orders are transfer orders under the hood, so they are deleted + through the stock transfer API. The server only allows deleting orders + that have not been completed yet. + */ + async deletePutawayOrder(orderId: string) { + const apiResponse = await this.request.delete( + STOCK_TRANSFER_BY_ID(orderId) + ); + if (!apiResponse.ok()) { + throw new Error( + `Problem deleting putaway order ${orderId}: ${apiResponse.status()}` + ); + } + } } export default PutawayService; diff --git a/src/constants/apiUrls.ts b/src/constants/apiUrls.ts index b661ac7..0b0d6da 100644 --- a/src/constants/apiUrls.ts +++ b/src/constants/apiUrls.ts @@ -40,6 +40,12 @@ export const STOCK_MOVEMENT_ITEMS = (id: string) => // PUTAWAY export const PUTAWAY_API = `${API}/putaways`; +export const PUTAWAY_BY_ID = (id: string) => `${PUTAWAY_API}/${id}`; + +// STOCK TRANSFER +export const STOCK_TRANSFER_API = `${API}/stockTransfers`; +export const STOCK_TRANSFER_BY_ID = (id: string) => + `${STOCK_TRANSFER_API}/${id}`; // PARTIAL RECEIVING export const PARTIAL_RECEIVING_BY_ID = (id: string) => diff --git a/src/pages/putaway/CreatePutawayPage.ts b/src/pages/putaway/CreatePutawayPage.ts index dc193b1..102b49e 100644 --- a/src/pages/putaway/CreatePutawayPage.ts +++ b/src/pages/putaway/CreatePutawayPage.ts @@ -39,6 +39,22 @@ class CreatePutawayPage extends BasePageModel { return this.page.getByTestId('start-putaway').nth(0); } + /** + Clicks "Start Putaway" and returns the id of the pending putaway order + created by the click, so that the test can delete the putaway via API + even when it fails before completing it. + */ + async startPutaway(): Promise { + const createResponsePromise = this.page.waitForResponse( + (response) => + response.url().includes('/api/putaways') && + response.request().method() === 'POST' + ); + await this.startPutawayButton.click(); + const createResponse = await createResponsePromise; + return (await createResponse.json()).data.id; + } + get showByStockMovementFilter() { return this.page.getByTestId('show-by-button'); } diff --git a/src/types.d.ts b/src/types.d.ts index 9265f48..12d2d7d 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -34,6 +34,13 @@ type StockMovementListResponse = { totalCount: number; }; +// GET /api/putaways/ +type PutawayResponse = { + id: string; + putawayNumber?: string | null; + putawayStatus?: string | null; +}; + // GET /api/putaways returns rows flattened into dotted keys // (e.g. "product.name"), not nested objects type PutawayCandidate = { diff --git a/src/utils/putawayUtils.ts b/src/utils/putawayUtils.ts new file mode 100644 index 0000000..5ac8c4a --- /dev/null +++ b/src/utils/putawayUtils.ts @@ -0,0 +1,59 @@ +import { TestInfo } from '@playwright/test'; + +import PutawayService from '@/api/PutawayService'; + +/** + Deletes the putaway order when it is still pending. Returns true when a + pending putaway was deleted, false when there was nothing to delete (the + putaway was completed, or was already removed within the test body). +*/ +async function deletePutawayOrderIfPending( + putawayService: PutawayService, + putawayOrderId: string +): Promise { + const putaway = await putawayService.getPutaway(putawayOrderId); + if (putaway?.data?.putawayStatus !== 'PENDING') { + return false; + } + await putawayService.deletePutawayOrder(putawayOrderId); + return true; +} + +/** + Shared afterEach cleanup for putaway tests. Extends the hook timeout first (a + failed test may have used up most of the shared test timeout), then deletes + every recorded putaway order that is still pending, so a putaway stuck by a + mid-test failure never leaks to the next test. + + Returns flags describing what the deletes found, so callers can tell whether + the transactions created by completing a putaway exist and can be removed — + deleting transaction rows by position after a mid-test failure would peel + unrelated rows instead. +*/ +export async function cleanupPendingPutaways({ + putawayService, + putawayOrderIds, + testInfo, +}: { + putawayService: PutawayService; + putawayOrderIds: string[]; + testInfo: TestInfo; +}) { + testInfo.setTimeout(testInfo.timeout + 60_000); + + const deletedPendingPutaways = []; + for (const putawayOrderId of putawayOrderIds) { + deletedPendingPutaways.push( + await deletePutawayOrderIfPending(putawayService, putawayOrderId) + ); + } + + return { + allPutawaysCompleted: + putawayOrderIds.length > 0 && + deletedPendingPutaways.every((wasPending) => !wasPending), + anyPutawayCompleted: deletedPendingPutaways.some( + (wasPending) => !wasPending + ), + }; +} From 23c21e2226e352962788fb49e71b2563e5d1c370 Mon Sep 17 00:00:00 2001 From: Katarzyna Date: Fri, 10 Jul 2026 11:03:54 +0200 Subject: [PATCH 5/6] update afterEach in putaway tests --- src/tests/putaway/addCommentToPutaway.test.ts | 47 +++++++---- ...ssertAttemptToEditCompletedPutaway.test.ts | 47 +++++++---- .../putaway/assertPutawayDetailsPage.test.ts | 47 +++++++---- ...rtReceivingBinsOnCreatePutawayPage.test.ts | 39 ++++++--- .../putaway/assertZonesInPutaways.test.ts | 57 ++++++++----- .../changeLocationOnCreatePutawayPage.test.ts | 42 +++++----- ...eateMoreThan1PutawayForTheSameItem.test.ts | 49 ++++++++---- src/tests/putaway/createPutaway.test.ts | 47 +++++++---- .../putaway/deleteItemsFromPutaway.test.ts | 39 ++++++--- .../putaway/deletePendingPutaway.test.ts | 39 ++++++--- .../performPutawayAsManagerUser.test.ts | 41 +++++++--- .../putaway/putawayImtemWithEmptyLot.test.ts | 39 ++++++--- .../putaway/putawayMoreThan1Item.test.ts | 79 +++++++++++++------ src/tests/putaway/putawayToHoldBin.test.ts | 55 ++++++++----- .../putaway/putawayToPreferredBin.test.ts | 47 +++++++---- .../putaway/qtyValidationsInPutaways.test.ts | 41 +++++----- ...lbackLastReceiptWhenPutawayCreated.test.ts | 47 +++++++---- ...ByCurrentPreferredAndOriginalOrder.test.ts | 53 ++++++------- src/tests/putaway/splitLineInPutaway.test.ts | 55 ++++++++----- ...dationOnQtyRemovedFromReceivingBin.test.ts | 39 ++++++--- 20 files changed, 602 insertions(+), 347 deletions(-) diff --git a/src/tests/putaway/addCommentToPutaway.test.ts b/src/tests/putaway/addCommentToPutaway.test.ts index a1270b8..475818d 100644 --- a/src/tests/putaway/addCommentToPutaway.test.ts +++ b/src/tests/putaway/addCommentToPutaway.test.ts @@ -3,6 +3,7 @@ import { ShipmentType } from '@/constants/ShipmentType'; import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -12,6 +13,7 @@ import { test.describe('Add comment to Putaway', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; test.beforeEach( async ({ @@ -20,6 +22,7 @@ test.describe('Add comment to Putaway', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -57,21 +60,33 @@ test.describe('Add comment to Putaway', () => { ); 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(); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + 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 deleteReceivedShipment({ stockMovementShowPage, @@ -115,7 +130,7 @@ test.describe('Add comment to Putaway', () => { await test.step('Start putaway', async () => { await createPutawayPage.table.row(0).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/assertAttemptToEditCompletedPutaway.test.ts b/src/tests/putaway/assertAttemptToEditCompletedPutaway.test.ts index 1ca9b65..d7e9991 100644 --- a/src/tests/putaway/assertAttemptToEditCompletedPutaway.test.ts +++ b/src/tests/putaway/assertAttemptToEditCompletedPutaway.test.ts @@ -3,6 +3,7 @@ import { ShipmentType } from '@/constants/ShipmentType'; import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -12,6 +13,7 @@ import { test.describe('Assert attempt to edit completed putaway', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; test.beforeEach( async ({ @@ -20,6 +22,7 @@ test.describe('Assert attempt to edit completed putaway', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -57,21 +60,33 @@ test.describe('Assert attempt to edit completed putaway', () => { ); 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(); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + 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 deleteReceivedShipment({ stockMovementShowPage, @@ -104,7 +119,7 @@ test.describe('Assert attempt to edit completed putaway', () => { await test.step('Start putaway', async () => { await createPutawayPage.table.row(0).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/assertPutawayDetailsPage.test.ts b/src/tests/putaway/assertPutawayDetailsPage.test.ts index 839776f..42972c5 100644 --- a/src/tests/putaway/assertPutawayDetailsPage.test.ts +++ b/src/tests/putaway/assertPutawayDetailsPage.test.ts @@ -8,6 +8,7 @@ import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; import { deleteFile, writeBufferToFile } from '@/utils/FileIOUtils'; import { pdfContainsValues } from '@/utils/pdfUtils'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -18,6 +19,7 @@ import { captureRowValues } from '@/utils/tableUtils'; test.describe('Assert putaway details page', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; const downloadedFilePaths: string[] = []; let expectedPdfValues: string[] = []; @@ -28,6 +30,7 @@ test.describe('Assert putaway details page', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -65,21 +68,33 @@ test.describe('Assert putaway details page', () => { ); 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(); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + 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 deleteReceivedShipment({ stockMovementShowPage, @@ -128,7 +143,7 @@ test.describe('Assert putaway details page', () => { await test.step('Start putaway', async () => { await createPutawayPage.table.row(0).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/assertReceivingBinsOnCreatePutawayPage.test.ts b/src/tests/putaway/assertReceivingBinsOnCreatePutawayPage.test.ts index 2291011..305f588 100644 --- a/src/tests/putaway/assertReceivingBinsOnCreatePutawayPage.test.ts +++ b/src/tests/putaway/assertReceivingBinsOnCreatePutawayPage.test.ts @@ -4,6 +4,7 @@ import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; import { formatDate, getDateByOffset } from '@/utils/DateUtils'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -17,6 +18,7 @@ test.describe('Assert receiving bin on create putaway page', () => { let SECONDARY_STOCK_MOVEMENT: StockMovementResponse; const uniqueIdentifier = new UniqueIdentifier(); const lot = uniqueIdentifier.generateUniqueString('lot'); + let PUTAWAY_ORDER_IDS: string[] = []; test.beforeEach( async ({ @@ -25,6 +27,7 @@ test.describe('Assert receiving bin on create putaway page', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); await test.step('Create 1st stock movement', async () => { @@ -123,17 +126,29 @@ test.describe('Assert receiving bin on create putaway page', () => { ); test.afterEach( - async ({ - stockMovementShowPage, - stockMovementService, - navbar, - transactionListPage, - oldViewShipmentPage, - }) => { - await navbar.configurationButton.click(); - await navbar.transactions.click(); - for (let n = 1; n < 4; n++) { - await transactionListPage.deleteTransaction(1); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + await navbar.configurationButton.click(); + await navbar.transactions.click(); + for (let n = 1; n < 4; n++) { + await transactionListPage.deleteTransaction(1); + } } await deleteReceivedShipment({ @@ -299,7 +314,7 @@ test.describe('Assert receiving bin on create putaway page', () => { await test.step('Start putaway', async () => { await createPutawayPage.table.row(1).checkbox.click(); await createPutawayPage.table.row(2).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/assertZonesInPutaways.test.ts b/src/tests/putaway/assertZonesInPutaways.test.ts index a454969..1ecdb44 100644 --- a/src/tests/putaway/assertZonesInPutaways.test.ts +++ b/src/tests/putaway/assertZonesInPutaways.test.ts @@ -8,6 +8,7 @@ import { Product } from '@/generated/ProductCodes.generated'; import { ProductResponse, StockMovementResponse } from '@/types'; import { deleteFile, writeBufferToFile } from '@/utils/FileIOUtils'; import { extractPdfColumnValues } from '@/utils/pdfUtils'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -24,6 +25,7 @@ test.describe('Assert zones on putaway pages', () => { const uniqueIdentifier = new UniqueIdentifier(); const zoneLocationName = uniqueIdentifier.generateUniqueString('zone'); const downloadedFilePaths: string[] = []; + let PUTAWAY_ORDER_IDS: string[] = []; test.beforeEach( async ({ @@ -39,6 +41,7 @@ test.describe('Assert zones on putaway pages', () => { locationListPage, createLocationPage, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); const mainLocation = await mainLocationService.getLocation(); const internalLocation = await internalLocationService.getLocation(); @@ -145,25 +148,37 @@ test.describe('Assert zones on putaway pages', () => { ); test.afterEach( - async ({ - stockMovementShowPage, - stockMovementService, - navbar, - transactionListPage, - oldViewShipmentPage, - productService, - productShowPage, - productEditPage, - page, - locationListPage, - mainLocationService, - createLocationPage, - internalLocationService, - }) => { - await navbar.configurationButton.click(); - await navbar.transactions.click(); - for (let n = 1; n < 4; n++) { - await transactionListPage.deleteTransaction(1); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + productService, + productShowPage, + productEditPage, + page, + locationListPage, + mainLocationService, + createLocationPage, + internalLocationService, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + await navbar.configurationButton.click(); + await navbar.transactions.click(); + for (let n = 1; n < 4; n++) { + await transactionListPage.deleteTransaction(1); + } } await deleteReceivedShipment({ stockMovementShowPage, @@ -265,7 +280,7 @@ test.describe('Assert zones on putaway pages', () => { .getExpandBinLocation(receivingBin) .click(); await createPutawayPage.table.row(1).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); await createPutawayPage.startStep.table.row(0).editButton.click(); await createPutawayPage.startStep.table.row(0).quantityInput.fill('5'); @@ -349,7 +364,7 @@ test.describe('Assert zones on putaway pages', () => { .click(); await createPutawayPage.table.row(1).checkbox.click(); await createPutawayPage.table.row(2).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/changeLocationOnCreatePutawayPage.test.ts b/src/tests/putaway/changeLocationOnCreatePutawayPage.test.ts index 485deae..6aa2658 100644 --- a/src/tests/putaway/changeLocationOnCreatePutawayPage.test.ts +++ b/src/tests/putaway/changeLocationOnCreatePutawayPage.test.ts @@ -3,6 +3,7 @@ import { ShipmentType } from '@/constants/ShipmentType'; import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -12,7 +13,7 @@ import { test.describe('Change location on putaway create page and list pages', () => { let STOCK_MOVEMENT: StockMovementResponse; - let putawayOrderIdentifier: string | undefined; + let PUTAWAY_ORDER_IDS: string[] = []; test.beforeEach( async ({ @@ -21,7 +22,7 @@ test.describe('Change location on putaway create page and list pages', () => { productService, receivingService, }) => { - putawayOrderIdentifier = undefined; + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -59,22 +60,20 @@ test.describe('Change location on putaway create page and list pages', () => { ); test.afterEach( - async ({ - stockMovementShowPage, - stockMovementService, - putawayListPage, - oldViewShipmentPage, - }) => { - // the received shipment must be cleaned up even when the test fails - // before the putaway is created - if (putawayOrderIdentifier) { - await putawayListPage.goToPage(); - await putawayListPage.table - .rowByOrderNumber(`${putawayOrderIdentifier}`.toString().trim()) - .actionsButton.click(); - await putawayListPage.table.clickDeleteOrderButton(1); - await putawayListPage.emptyPutawayList.isVisible(); - } + async ( + { + stockMovementShowPage, + stockMovementService, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); await deleteReceivedShipment({ stockMovementShowPage, @@ -156,13 +155,12 @@ test.describe('Change location on putaway create page and list pages', () => { .getExpandBinLocation(receivingBin) .click(); await createPutawayPage.table.row(1).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); - putawayOrderIdentifier = - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - (await createPutawayPage.startStep.orderNumberValue.textContent())!; + const putawayOrderIdentifier = + await createPutawayPage.startStep.orderNumberValue.textContent(); const putawayOrderIdentifierContent = `${putawayOrderIdentifier}` .toString() diff --git a/src/tests/putaway/createMoreThan1PutawayForTheSameItem.test.ts b/src/tests/putaway/createMoreThan1PutawayForTheSameItem.test.ts index 9850927..dd4bb32 100644 --- a/src/tests/putaway/createMoreThan1PutawayForTheSameItem.test.ts +++ b/src/tests/putaway/createMoreThan1PutawayForTheSameItem.test.ts @@ -8,6 +8,7 @@ import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; import { deleteFile, writeBufferToFile } from '@/utils/FileIOUtils'; import { extractPdfColumnValues } from '@/utils/pdfUtils'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -17,6 +18,7 @@ import { test.describe('Create more than 1 putaway from the same item', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; const downloadedFilePaths: string[] = []; test.beforeEach( @@ -26,6 +28,7 @@ test.describe('Create more than 1 putaway from the same item', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -63,21 +66,33 @@ test.describe('Create more than 1 putaway from the same item', () => { ); 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(); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + 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 deleteReceivedShipment({ stockMovementShowPage, @@ -122,7 +137,7 @@ test.describe('Create more than 1 putaway from the same item', () => { await test.step('Start putaway', async () => { await createPutawayPage.table.row(0).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); @@ -204,7 +219,7 @@ test.describe('Create more than 1 putaway from the same item', () => { await test.step('Start putaway', async () => { await createPutawayPage.table.row(1).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/createPutaway.test.ts b/src/tests/putaway/createPutaway.test.ts index ab23dc7..09f8f1b 100644 --- a/src/tests/putaway/createPutaway.test.ts +++ b/src/tests/putaway/createPutaway.test.ts @@ -8,6 +8,7 @@ import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; import { deleteFile, writeBufferToFile } from '@/utils/FileIOUtils'; import { extractPdfColumnValues } from '@/utils/pdfUtils'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -17,6 +18,7 @@ import { test.describe('Putaway received inbound shipment', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; const downloadedFilePaths: string[] = []; test.beforeEach( @@ -26,6 +28,7 @@ test.describe('Putaway received inbound shipment', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -63,21 +66,33 @@ test.describe('Putaway received inbound shipment', () => { ); 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(); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + 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 deleteReceivedShipment({ stockMovementShowPage, @@ -121,7 +136,7 @@ test.describe('Putaway received inbound shipment', () => { await test.step('Start putaway', async () => { await createPutawayPage.table.row(0).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/deleteItemsFromPutaway.test.ts b/src/tests/putaway/deleteItemsFromPutaway.test.ts index 3fa7165..af9d676 100644 --- a/src/tests/putaway/deleteItemsFromPutaway.test.ts +++ b/src/tests/putaway/deleteItemsFromPutaway.test.ts @@ -3,6 +3,7 @@ import { ShipmentType } from '@/constants/ShipmentType'; import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { ProductResponse, StockMovementResponse } from '@/types'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -13,6 +14,7 @@ import { byNameAsc } from '@/utils/sortUtils'; test.describe('Delete items from putaway', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; let product: ProductResponse; let product2: ProductResponse; @@ -23,6 +25,7 @@ test.describe('Delete items from putaway', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -71,17 +74,29 @@ test.describe('Delete items from putaway', () => { ); test.afterEach( - async ({ - stockMovementShowPage, - stockMovementService, - navbar, - transactionListPage, - oldViewShipmentPage, - }) => { - await navbar.configurationButton.click(); - await navbar.transactions.click(); - for (let n = 1; n < 3; n++) { - await transactionListPage.deleteTransaction(1); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + await navbar.configurationButton.click(); + await navbar.transactions.click(); + for (let n = 1; n < 3; n++) { + await transactionListPage.deleteTransaction(1); + } } await deleteReceivedShipment({ stockMovementShowPage, @@ -128,7 +143,7 @@ test.describe('Delete items from putaway', () => { ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); await createPutawayPage.table.row(2).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/deletePendingPutaway.test.ts b/src/tests/putaway/deletePendingPutaway.test.ts index 4004ac4..d958b0c 100644 --- a/src/tests/putaway/deletePendingPutaway.test.ts +++ b/src/tests/putaway/deletePendingPutaway.test.ts @@ -8,6 +8,7 @@ import PutawayListPage from '@/pages/putaway/list/PutawayListPage'; import PutawayDetailsPage from '@/pages/putaway/putawayDetails/PutawayDetailsPage'; import StockMovementShowPage from '@/pages/stockMovementShow/StockMovementShowPage'; import { StockMovementResponse } from '@/types'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -17,6 +18,7 @@ import { test.describe('Delete pending putaways', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; test.beforeEach( async ({ @@ -25,6 +27,7 @@ test.describe('Delete pending putaways', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -62,11 +65,21 @@ test.describe('Delete pending putaways', () => { ); test.afterEach( - async ({ - stockMovementShowPage, - stockMovementService, - oldViewShipmentPage, - }) => { + async ( + { + stockMovementShowPage, + stockMovementService, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + await deleteReceivedShipment({ stockMovementShowPage, oldViewShipmentPage, @@ -108,7 +121,7 @@ test.describe('Delete pending putaways', () => { createPutawayPage.table.row(1).getProductName(product.name) ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); @@ -171,7 +184,7 @@ test.describe('Delete pending putaways', () => { createPutawayPage.table.row(1).getProductName(product.name) ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); @@ -242,7 +255,7 @@ test.describe('Delete pending putaways', () => { createPutawayPage.table.row(1).getProductName(product.name) ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); @@ -310,7 +323,7 @@ test.describe('Delete pending putaways', () => { createPutawayPage.table.row(1).getProductName(product.name) ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); @@ -384,7 +397,7 @@ test.describe('Delete pending putaways', () => { createPutawayPage.table.row(1).getProductName(product.name) ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); @@ -452,7 +465,7 @@ test.describe('Delete pending putaways', () => { createPutawayPage.table.row(1).getProductName(product.name) ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); @@ -526,7 +539,7 @@ test.describe('Delete pending putaways', () => { createPutawayPage.table.row(1).getProductName(product.name) ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); @@ -594,7 +607,7 @@ test.describe('Delete pending putaways', () => { createPutawayPage.table.row(1).getProductName(product.name) ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/performPutawayAsManagerUser.test.ts b/src/tests/putaway/performPutawayAsManagerUser.test.ts index ddf5901..29d7a9a 100644 --- a/src/tests/putaway/performPutawayAsManagerUser.test.ts +++ b/src/tests/putaway/performPutawayAsManagerUser.test.ts @@ -7,6 +7,7 @@ import CreatePutawayPage from '@/pages/putaway/CreatePutawayPage'; import PutawayDetailsPage from '@/pages/putaway/putawayDetails/PutawayDetailsPage'; import StockMovementShowPage from '@/pages/stockMovementShow/StockMovementShowPage'; import { ProductResponse, StockMovementResponse } from '@/types'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -17,6 +18,7 @@ import { byNameAsc } from '@/utils/sortUtils'; test.describe('Perform putaway as manager user', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; let product: ProductResponse; let product2: ProductResponse; @@ -27,6 +29,7 @@ test.describe('Perform putaway as manager user', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -75,18 +78,30 @@ test.describe('Perform putaway as manager user', () => { ); test.afterEach( - async ({ - stockMovementShowPage, - stockMovementService, - navbar, - transactionListPage, - oldViewShipmentPage, - }) => { + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + await stockMovementShowPage.goToPage(STOCK_MOVEMENT.id); - await navbar.configurationButton.click(); - await navbar.transactions.click(); - await transactionListPage.deleteTransaction(1); - await transactionListPage.deleteTransaction(1); + if (allPutawaysCompleted) { + await navbar.configurationButton.click(); + await navbar.transactions.click(); + await transactionListPage.deleteTransaction(1); + await transactionListPage.deleteTransaction(1); + } await deleteReceivedShipment({ stockMovementShowPage, oldViewShipmentPage, @@ -134,7 +149,7 @@ test.describe('Perform putaway as manager user', () => { ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); await createPutawayPage.table.row(2).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); @@ -255,7 +270,7 @@ test.describe('Perform putaway as manager user', () => { await test.step('Start putaway', async () => { await createPutawayPageManagerUser.table.row(0).checkbox.click(); - await createPutawayPageManagerUser.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPageManagerUser.startPutaway()); await createPutawayPageManagerUser.startStep.isLoaded(); }); diff --git a/src/tests/putaway/putawayImtemWithEmptyLot.test.ts b/src/tests/putaway/putawayImtemWithEmptyLot.test.ts index ad7cc90..4df04fb 100644 --- a/src/tests/putaway/putawayImtemWithEmptyLot.test.ts +++ b/src/tests/putaway/putawayImtemWithEmptyLot.test.ts @@ -3,6 +3,7 @@ import { ShipmentType } from '@/constants/ShipmentType'; import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -12,6 +13,7 @@ import { test.describe('Putaway item with empty lot', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; test.beforeEach( async ({ @@ -20,6 +22,7 @@ test.describe('Putaway item with empty lot', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -57,17 +60,29 @@ test.describe('Putaway item with empty lot', () => { ); test.afterEach( - async ({ - stockMovementShowPage, - stockMovementService, - navbar, - transactionListPage, - oldViewShipmentPage, - }) => { - await navbar.configurationButton.click(); - await navbar.transactions.click(); - for (let n = 1; n < 5; n++) { - await transactionListPage.deleteTransaction(1); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + await navbar.configurationButton.click(); + await navbar.transactions.click(); + for (let n = 1; n < 5; n++) { + await transactionListPage.deleteTransaction(1); + } } await deleteReceivedShipment({ stockMovementShowPage, @@ -161,7 +176,7 @@ test.describe('Putaway item with empty lot', () => { await test.step('Start putaway', async () => { await createPutawayPage.table.row(1).checkbox.click(); await createPutawayPage.table.row(2).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/putawayMoreThan1Item.test.ts b/src/tests/putaway/putawayMoreThan1Item.test.ts index e885246..a1930f3 100644 --- a/src/tests/putaway/putawayMoreThan1Item.test.ts +++ b/src/tests/putaway/putawayMoreThan1Item.test.ts @@ -3,6 +3,7 @@ import { ShipmentType } from '@/constants/ShipmentType'; import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { ProductResponse, StockMovementResponse } from '@/types'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -13,6 +14,7 @@ import { byNameAsc } from '@/utils/sortUtils'; test.describe('Create putaway for more than 1 item, separate putaways', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; let product: ProductResponse; let product2: ProductResponse; @@ -23,6 +25,7 @@ test.describe('Create putaway for more than 1 item, separate putaways', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -71,17 +74,29 @@ test.describe('Create putaway for more than 1 item, separate putaways', () => { ); test.afterEach( - async ({ - stockMovementShowPage, - stockMovementService, - navbar, - transactionListPage, - oldViewShipmentPage, - }) => { - await navbar.configurationButton.click(); - await navbar.transactions.click(); - for (let n = 1; n < 4; n++) { - await transactionListPage.deleteTransaction(1); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + await navbar.configurationButton.click(); + await navbar.transactions.click(); + for (let n = 1; n < 4; n++) { + await transactionListPage.deleteTransaction(1); + } } await deleteReceivedShipment({ stockMovementShowPage, @@ -132,7 +147,7 @@ test.describe('Create putaway for more than 1 item, separate putaways', () => { createPutawayPage.table.row(2).getProductName(product2.name) ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); @@ -215,7 +230,7 @@ test.describe('Create putaway for more than 1 item, separate putaways', () => { createPutawayPage.table.row(1).getProductName(product2.name) ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); @@ -259,6 +274,7 @@ test.describe('Create putaway for more than 1 item, separate putaways', () => { test.describe('Putaway 2 items in the same putaway', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; let product: ProductResponse; let product2: ProductResponse; @@ -269,6 +285,7 @@ test.describe('Putaway 2 items in the same putaway', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -317,17 +334,29 @@ test.describe('Putaway 2 items in the same putaway', () => { ); test.afterEach( - async ({ - stockMovementShowPage, - stockMovementService, - navbar, - transactionListPage, - oldViewShipmentPage, - }) => { - await navbar.configurationButton.click(); - await navbar.transactions.click(); - await transactionListPage.deleteTransaction(1); - await transactionListPage.deleteTransaction(1); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + await navbar.configurationButton.click(); + await navbar.transactions.click(); + await transactionListPage.deleteTransaction(1); + await transactionListPage.deleteTransaction(1); + } await stockMovementShowPage.goToPage(STOCK_MOVEMENT.id); await stockMovementShowPage.detailsListTable.oldViewShipmentPage.click(); await oldViewShipmentPage.undoStatusChangeButton.click(); @@ -381,7 +410,7 @@ test.describe('Putaway 2 items in the same putaway', () => { ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); await createPutawayPage.table.row(2).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/putawayToHoldBin.test.ts b/src/tests/putaway/putawayToHoldBin.test.ts index 993cde4..2d9afc9 100644 --- a/src/tests/putaway/putawayToHoldBin.test.ts +++ b/src/tests/putaway/putawayToHoldBin.test.ts @@ -4,6 +4,7 @@ import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; import BinLocationUtils from '@/utils/BinLocationUtils'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -16,6 +17,7 @@ test.describe('Putaway item into hold bin', () => { test.describe.configure({ timeout: 60000 }); //timeout has been added for this test to make sure that the content on bin location tab will load as it can include a lot of data let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; const uniqueIdentifier = new UniqueIdentifier(); const holdBinLocationName = uniqueIdentifier.generateUniqueString('holdbin'); @@ -30,6 +32,7 @@ test.describe('Putaway item into hold bin', () => { locationListPage, createLocationPage, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); const product = await productService.getProduct(Product.FIVE); @@ -77,27 +80,39 @@ test.describe('Putaway item into hold bin', () => { ); test.afterEach( - async ({ - navbar, - transactionListPage, - stockMovementShowPage, - stockMovementService, - page, - locationListPage, - mainLocationService, - createLocationPage, - oldViewShipmentPage, - }) => { + async ( + { + navbar, + transactionListPage, + stockMovementShowPage, + stockMovementService, + page, + locationListPage, + mainLocationService, + createLocationPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + const receivingBin = AppConfig.instance.receivingBinPrefix + STOCK_MOVEMENT.identifier; - 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(); + if (allPutawaysCompleted) { + 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 deleteReceivedShipment({ stockMovementShowPage, @@ -151,7 +166,7 @@ test.describe('Putaway item into hold bin', () => { await test.step('Start putaway', async () => { await createPutawayPage.table.row(0).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/putawayToPreferredBin.test.ts b/src/tests/putaway/putawayToPreferredBin.test.ts index 1087d8d..3c77370 100644 --- a/src/tests/putaway/putawayToPreferredBin.test.ts +++ b/src/tests/putaway/putawayToPreferredBin.test.ts @@ -8,6 +8,7 @@ import { Product } from '@/generated/ProductCodes.generated'; import { ProductResponse, StockMovementResponse } from '@/types'; import { deleteFile, writeBufferToFile } from '@/utils/FileIOUtils'; import { extractPdfColumnValues } from '@/utils/pdfUtils'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -18,6 +19,7 @@ import { byNameAsc } from '@/utils/sortUtils'; test.describe('Putaway to preferred bin and default bin', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; let product: ProductResponse; let product2: ProductResponse; const downloadedFilePaths: string[] = []; @@ -32,6 +34,7 @@ test.describe('Putaway to preferred bin and default bin', () => { productEditPage, internalLocationService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -92,20 +95,32 @@ test.describe('Putaway to preferred bin and default bin', () => { ); test.afterEach( - async ({ - stockMovementShowPage, - stockMovementService, - navbar, - transactionListPage, - oldViewShipmentPage, - productService, - productShowPage, - productEditPage, - }) => { - await navbar.configurationButton.click(); - await navbar.transactions.click(); - await transactionListPage.deleteTransaction(1); - await transactionListPage.deleteTransaction(1); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + productService, + productShowPage, + productEditPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + await navbar.configurationButton.click(); + await navbar.transactions.click(); + await transactionListPage.deleteTransaction(1); + await transactionListPage.deleteTransaction(1); + } await deleteReceivedShipment({ stockMovementShowPage, oldViewShipmentPage, @@ -161,7 +176,7 @@ test.describe('Putaway to preferred bin and default bin', () => { .click(); await createPutawayPage.table.row(1).checkbox.click(); await createPutawayPage.table.row(2).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); @@ -287,7 +302,7 @@ test.describe('Putaway to preferred bin and default bin', () => { .getExpandBinLocation(receivingBin) .click(); await createPutawayPage.table.row(2).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/qtyValidationsInPutaways.test.ts b/src/tests/putaway/qtyValidationsInPutaways.test.ts index f1230dc..3094c29 100644 --- a/src/tests/putaway/qtyValidationsInPutaways.test.ts +++ b/src/tests/putaway/qtyValidationsInPutaways.test.ts @@ -3,6 +3,7 @@ import { ShipmentType } from '@/constants/ShipmentType'; import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -12,7 +13,7 @@ import { test.describe('Assert qty validations in putaways', () => { let STOCK_MOVEMENT: StockMovementResponse; - let putawayOrderIdentifier: string | undefined; + let PUTAWAY_ORDER_IDS: string[] = []; test.beforeEach( async ({ @@ -21,7 +22,7 @@ test.describe('Assert qty validations in putaways', () => { productService, receivingService, }) => { - putawayOrderIdentifier = undefined; + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -59,22 +60,20 @@ test.describe('Assert qty validations in putaways', () => { ); test.afterEach( - async ({ - putawayListPage, - stockMovementShowPage, - stockMovementService, - oldViewShipmentPage, - }) => { - // the received shipment must be cleaned up even when the test fails - // before the putaway is started - if (putawayOrderIdentifier) { - await putawayListPage.goToPage(); - await putawayListPage.table - .rowByOrderNumber(`${putawayOrderIdentifier}`.toString().trim()) - .actionsButton.click(); - await putawayListPage.table.clickDeleteOrderButton(1); - await putawayListPage.emptyPutawayList.isVisible(); - } + async ( + { + stockMovementShowPage, + stockMovementService, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); await deleteReceivedShipment({ stockMovementShowPage, @@ -109,14 +108,10 @@ test.describe('Assert qty validations in putaways', () => { await test.step('Start putaway', async () => { await createPutawayPage.table.row(0).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); - putawayOrderIdentifier = - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - (await createPutawayPage.startStep.orderNumberValue.textContent())!; - await test.step('Try to edit qty to higher and assert validations', async () => { await createPutawayPage.startStep.table.row(0).editButton.click(); await createPutawayPage.startStep.table.row(0).quantityInput.fill('20'); diff --git a/src/tests/putaway/rollbackLastReceiptWhenPutawayCreated.test.ts b/src/tests/putaway/rollbackLastReceiptWhenPutawayCreated.test.ts index c117515..591dd5a 100644 --- a/src/tests/putaway/rollbackLastReceiptWhenPutawayCreated.test.ts +++ b/src/tests/putaway/rollbackLastReceiptWhenPutawayCreated.test.ts @@ -3,6 +3,7 @@ import { ShipmentType } from '@/constants/ShipmentType'; import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -12,6 +13,7 @@ import { test.describe('Rollback last receipt behavior when putaway created', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; test.beforeEach( async ({ @@ -20,6 +22,7 @@ test.describe('Rollback last receipt behavior when putaway created', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -57,21 +60,33 @@ test.describe('Rollback last receipt behavior when putaway created', () => { ); 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(); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + 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 deleteReceivedShipment({ stockMovementShowPage, oldViewShipmentPage, @@ -107,7 +122,7 @@ test.describe('Rollback last receipt behavior when putaway created', () => { await test.step('Start putaway', async () => { await createPutawayPage.table.row(0).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/sortPutawayByCurrentPreferredAndOriginalOrder.test.ts b/src/tests/putaway/sortPutawayByCurrentPreferredAndOriginalOrder.test.ts index 398e903..af10b79 100644 --- a/src/tests/putaway/sortPutawayByCurrentPreferredAndOriginalOrder.test.ts +++ b/src/tests/putaway/sortPutawayByCurrentPreferredAndOriginalOrder.test.ts @@ -6,6 +6,7 @@ import { StockMovementResponse, } from '@/types'; import { assignPreferredBin } from '@/utils/productUtils'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, receiveInbound } from '@/utils/shipmentUtils'; import { byNameAsc } from '@/utils/sortUtils'; @@ -31,7 +32,7 @@ test.describe('Sort putaway by current bin, preferred bin and original order', ( let binOne: LocationResponse; let binTwo: LocationResponse; - let putawayOrderIdentifier: string | undefined; + let PUTAWAY_ORDER_IDS: string[] = []; test.beforeEach( async ({ @@ -44,7 +45,7 @@ test.describe('Sort putaway by current bin, preferred bin and original order', ( productShowPage, productEditPage, }) => { - putawayOrderIdentifier = undefined; + PUTAWAY_ORDER_IDS = []; inboundTwo = undefined; [productA, productB, productC] = [ await productService.getProduct(Product.ONE), @@ -87,28 +88,26 @@ test.describe('Sort putaway by current bin, preferred bin and original order', ( ); test.afterEach( - async ({ - stockMovementShowPage, - stockMovementService, - oldViewShipmentPage, - navbar, - transactionListPage, - putawayListPage, - productShowPage, - productEditPage, - }) => { - // Remove the pending 2nd putaway and the 3 transactions created along - // the way; they exist only once the 2nd putaway has been started, but - // the shipments and preferred bins must be cleaned up regardless of - // how far the test got - if (putawayOrderIdentifier) { - await putawayListPage.goToPage(); - await putawayListPage.isLoaded(); - await putawayListPage.table - .rowByOrderNumber(`${putawayOrderIdentifier}`.toString().trim()) - .actionsButton.click(); - await putawayListPage.table.clickDeleteOrderButton(1); + async ( + { + stockMovementShowPage, + stockMovementService, + oldViewShipmentPage, + navbar, + transactionListPage, + putawayService, + productShowPage, + productEditPage, + }, + testInfo + ) => { + const { anyPutawayCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + if (anyPutawayCompleted) { await navbar.configurationButton.click(); await navbar.transactions.click(); for (let i = 0; i < 3; i++) { @@ -172,7 +171,7 @@ test.describe('Sort putaway by current bin, preferred bin and original order', ( await createPutawayPage.table .rowByProductName(productA.name) .checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); // Putaway A into binTwo (its preferred bin is auto-suggested). @@ -225,14 +224,10 @@ test.describe('Sort putaway by current bin, preferred bin and original order', ( await createPutawayPage.table .rowByProductName(productC.name) .checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); - putawayOrderIdentifier = - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - (await createPutawayPage.startStep.orderNumberValue.textContent())!; - await test.step('assert original order of items', async () => { await expect(createPutawayPage.startStep.sortButton).toContainText( 'Sort by current bins' diff --git a/src/tests/putaway/splitLineInPutaway.test.ts b/src/tests/putaway/splitLineInPutaway.test.ts index 2cd5b49..fcc04a7 100644 --- a/src/tests/putaway/splitLineInPutaway.test.ts +++ b/src/tests/putaway/splitLineInPutaway.test.ts @@ -3,6 +3,7 @@ import { ShipmentType } from '@/constants/ShipmentType'; import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import { StockMovementResponse } from '@/types'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -12,6 +13,7 @@ import { test.describe('Split line in Putaway', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; test.beforeEach( async ({ @@ -20,6 +22,7 @@ test.describe('Split line in Putaway', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -57,24 +60,36 @@ test.describe('Split line in Putaway', () => { ); 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(); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + 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 deleteReceivedShipment({ stockMovementShowPage, @@ -112,7 +127,7 @@ test.describe('Split line in Putaway', () => { await test.step('Start putaway', async () => { await createPutawayPage.table.row(0).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); @@ -219,7 +234,7 @@ test.describe('Split line in Putaway', () => { await test.step('Start putaway', async () => { await createPutawayPage.table.row(0).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); diff --git a/src/tests/putaway/validationOnQtyRemovedFromReceivingBin.test.ts b/src/tests/putaway/validationOnQtyRemovedFromReceivingBin.test.ts index daa263c..a227826 100644 --- a/src/tests/putaway/validationOnQtyRemovedFromReceivingBin.test.ts +++ b/src/tests/putaway/validationOnQtyRemovedFromReceivingBin.test.ts @@ -6,6 +6,7 @@ import { expect, test } from '@/fixtures/fixtures'; import { Product } from '@/generated/ProductCodes.generated'; import ProductShowPage from '@/pages/product/productShow/ProductShowPage'; import { ProductResponse, StockMovementResponse } from '@/types'; +import { cleanupPendingPutaways } from '@/utils/putawayUtils'; import RefreshCachesUtils from '@/utils/RefreshCaches'; import { deleteReceivedShipment, @@ -16,6 +17,7 @@ import { byNameAsc } from '@/utils/sortUtils'; test.describe('Assert validation on qty removed from receiving bin', () => { let STOCK_MOVEMENT: StockMovementResponse; + let PUTAWAY_ORDER_IDS: string[] = []; let product: ProductResponse; let product2: ProductResponse; @@ -26,6 +28,7 @@ test.describe('Assert validation on qty removed from receiving bin', () => { productService, receivingService, }) => { + PUTAWAY_ORDER_IDS = []; const supplierLocation = await supplierLocationService.getLocation(); STOCK_MOVEMENT = await stockMovementService.createInbound({ originId: supplierLocation.id, @@ -74,17 +77,29 @@ test.describe('Assert validation on qty removed from receiving bin', () => { ); test.afterEach( - async ({ - stockMovementShowPage, - stockMovementService, - navbar, - transactionListPage, - oldViewShipmentPage, - }) => { - await navbar.configurationButton.click(); - await navbar.transactions.click(); - for (let n = 1; n < 6; n++) { - await transactionListPage.deleteTransaction(1); + async ( + { + stockMovementShowPage, + stockMovementService, + navbar, + transactionListPage, + oldViewShipmentPage, + putawayService, + }, + testInfo + ) => { + const { allPutawaysCompleted } = await cleanupPendingPutaways({ + putawayService, + putawayOrderIds: PUTAWAY_ORDER_IDS, + testInfo, + }); + + if (allPutawaysCompleted) { + await navbar.configurationButton.click(); + await navbar.transactions.click(); + for (let n = 1; n < 6; n++) { + await transactionListPage.deleteTransaction(1); + } } await deleteReceivedShipment({ stockMovementShowPage, @@ -153,7 +168,7 @@ test.describe('Assert validation on qty removed from receiving bin', () => { ).toBeVisible(); await createPutawayPage.table.row(1).checkbox.click(); await createPutawayPage.table.row(2).checkbox.click(); - await createPutawayPage.startPutawayButton.click(); + PUTAWAY_ORDER_IDS.push(await createPutawayPage.startPutaway()); await createPutawayPage.startStep.isLoaded(); }); From a5b056679fd19603a9dafa08836a159f29960234 Mon Sep 17 00:00:00 2001 From: Katarzyna Date: Fri, 10 Jul 2026 11:04:34 +0200 Subject: [PATCH 6/6] improve tabs on stockMovementShowPage --- .../StockMovementShowPage.ts | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/pages/stockMovementShow/StockMovementShowPage.ts b/src/pages/stockMovementShow/StockMovementShowPage.ts index a624464..2b8a60b 100644 --- a/src/pages/stockMovementShow/StockMovementShowPage.ts +++ b/src/pages/stockMovementShow/StockMovementShowPage.ts @@ -1,4 +1,4 @@ -import { expect, Page } from '@playwright/test'; +import { expect, Locator, Page } from '@playwright/test'; import { STOCK_MOVEMENT_URL } from '@/constants/applicationUrls'; import BasePageModel from '@/pages/BasePageModel'; @@ -112,25 +112,29 @@ class StockMovementShowPage extends BasePageModel { await this.deleteButton.click(); } - async openReceiptsTab() { - // tab content is fetched once per page load, so when it fails to render, - // re-clicking the tab never refetches it — only a reload does + // tab content is fetched once per page load, so when it fails to render, + // re-clicking the tab never refetches it — only a reload does + private async openTab( + tab: Locator, + tabContent: { isLoaded: () => Promise } + ) { let reloadOnRetry = false; await expect(async () => { if (reloadOnRetry) { await this.page.reload(); } reloadOnRetry = true; - await this.receiptTab.click(); - await this.receiptListTable.isLoaded(); - }).toPass({ timeout: 20000, intervals: [500, 1000, 2000] }); + await tab.click(); + await tabContent.isLoaded(); + }).toPass({ timeout: 45000, intervals: [500, 1000, 2000] }); + } + + async openReceiptsTab() { + await this.openTab(this.receiptTab, this.receiptListTable); } async openDocumentsTab() { - await expect(async () => { - await this.documentTab.click(); - await this.documentsListTable.isLoaded(); - }).toPass({ timeout: 20000, intervals: [500, 1000, 2000] }); + await this.openTab(this.documentTab, this.documentsListTable); } }