import { type Page, type Locator } from "@playwright/test"; import { fillDatePicker } from "../utils/date-picker"; export class InboundShipmentCreateFormPage { readonly page: Page; readonly purchaseOrderCombobox: Locator; readonly browseButton: Locator; readonly supplierInfo: Locator; readonly receiptDateInput: Locator; readonly linesTable: Locator; readonly fullyReceivedWarning: Locator; readonly submitButton: Locator; readonly cancelButton: Locator; // PO Browse dialog readonly browseDialog: Locator; readonly browseDialogFilterInput: Locator; readonly browseDialogSelectButton: Locator; readonly browseDialogCancelButton: Locator; constructor(page: Page) { this.page = page; this.purchaseOrderCombobox = page.getByPlaceholder("Search by supplier or PO number..."); this.browseButton = page.getByRole("button", { name: /browse/i }); this.supplierInfo = page.getByText("Supplier:"); this.receiptDateInput = page.getByLabel("Receipt Date"); this.linesTable = page.getByRole("table"); this.fullyReceivedWarning = page.getByText( "All items on this PO have been fully received. No PO lines to receive.", ); this.submitButton = page.getByRole("button", { name: /create inbound shipment|creating/i, }); // Top-level Cancel action (scoped to the form, not the browse dialog). this.cancelButton = page.locator("form").getByRole("button", { name: /cancel/i }); this.browseDialog = page.getByRole("dialog"); this.browseDialogFilterInput = this.browseDialog.getByPlaceholder( "Filter by supplier, PO number, SKU, item name...", ); this.browseDialogSelectButton = this.browseDialog.getByRole("button", { name: /select/i, }); this.browseDialogCancelButton = this.browseDialog.getByRole("button", { name: /cancel/i, }); } async goto() { await this.page.goto("/procurement/inbound-shipment/create"); } /** Open the Purchase Order combobox and select the first matching option. */ async selectPurchaseOrderByName(name: string) { await this.purchaseOrderCombobox.click(); await this.purchaseOrderCombobox.fill(name); const option = this.page.getByRole("option", { name: new RegExp(name, "i") }).first(); await option.waitFor({ state: "visible" }); await option.click(); } /** Open the Purchase Order combobox and select the first available option. */ async selectFirstPurchaseOrder() { await this.purchaseOrderCombobox.click(); const firstOption = this.page.getByRole("option").first(); await firstOption.waitFor({ state: "visible" }); await firstOption.click(); } /** Open the Browse dialog to pick a purchase order from a table. */ async openBrowseDialog() { await this.browseButton.click(); await this.browseDialog.waitFor({ state: "visible" }); } async filterBrowseDialog(term: string) { await this.browseDialogFilterInput.fill(term); } /** Click a purchase-order row in the Browse dialog by its cell text. */ async selectBrowseDialogRow(text: string) { await this.browseDialog.getByRole("row").filter({ hasText: text }).first().click(); } async confirmBrowseSelection() { await this.browseDialogSelectButton.click(); } async cancelBrowseDialog() { await this.browseDialogCancelButton.click(); } async fillReceiptDate(date: string) { await fillDatePicker(this.receiptDateInput, date); } /** The Receive Qty input for the line at the given zero-based row index. */ receiveQtyInput(rowIndex: number): Locator { return this.linesTable.locator("tbody tr").nth(rowIndex).getByRole("spinbutton"); } async setReceiveQty(rowIndex: number, quantity: string) { await this.receiveQtyInput(rowIndex).fill(quantity); } /** Remove the line at the given zero-based row index via its trash button. */ async removeLine(rowIndex: number) { await this.linesTable.locator("tbody tr").nth(rowIndex).getByRole("button").click(); } async submit() { await this.submitButton.click(); } async cancel() { await this.cancelButton.click(); } }