Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/api/BaseServiceModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ class BaseServiceModel {
constructor(request: APIRequestContext) {
this.request = request;
}

getRequestContext() {
return this.request;
}
}

export default BaseServiceModel;
11 changes: 7 additions & 4 deletions src/api/StockMovementService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,13 @@ class StockMovementService extends BaseServiceModel {
}

async deleteStockMovement(id: string) {
try {
await this.request.delete(STOCK_MOVEMENT_BY_ID(id));
} catch (error) {
throw new Error('Problem deleting stock movement');
// request.delete does not throw on HTTP error statuses, and a swallowed
// failed delete leaves the stock movement behind for the next tests
Comment thread
kkrawczyk123 marked this conversation as resolved.
const apiResponse = await this.request.delete(STOCK_MOVEMENT_BY_ID(id));
if (!apiResponse.ok()) {
throw new Error(
`Problem deleting stock movement ${id}: ${apiResponse.status()}`
);
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/fixtures/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import ProductEditPage from '@/pages/product/productEdit/ProductEditPage';
import ProductShowPage from '@/pages/product/productShow/ProductShowPage';
import CreatePutawayPage from '@/pages/putaway/CreatePutawayPage';
import PutawayListPage from '@/pages/putaway/list/PutawayListPage';
import AddCommentToPutawayPage from '@/pages/putaway/putawayDetails/AddCommentToPutawayPage';
import PutawayDetailsPage from '@/pages/putaway/putawayDetails/PutawayDetailsPage';
import ReceivingPage from '@/pages/receiving/ReceivingPage';
import OldViewShipmentPage from '@/pages/stockMovementShow/OldViewShipmentPage';
Expand Down Expand Up @@ -74,6 +75,7 @@ type Fixtures = {
putawayListPage: PutawayListPage;
productEditPage: ProductEditPage;
editTransactionPage: EditTransactionPage;
addCommentToPutawayPage: AddCommentToPutawayPage;
// COMPONENTS
navbar: Navbar;
locationChooser: LocationChooser;
Expand Down Expand Up @@ -153,6 +155,8 @@ export const test = baseTest.extend<Fixtures>({
productEditPage: async ({ page }, use) => use(new ProductEditPage(page)),
editTransactionPage: async ({ page }, use) =>
use(new EditTransactionPage(page)),
addCommentToPutawayPage: async ({ page }, use) =>
use(new AddCommentToPutawayPage(page)),
// COMPONENTS
navbar: async ({ page }, use) => use(new Navbar(page)),
locationChooser: async ({ page }, use) => use(new LocationChooser(page)),
Expand Down
2 changes: 1 addition & 1 deletion src/pages/product/productShow/ProductShowPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class ProductShowPage extends BasePageModel {
return this.page.getByRole('link', { name: 'Stock History' });
}

get editProductkButton() {
get editProductButton() {
return this.page.getByRole('link', { name: 'Edit Product' });
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/pages/putaway/list/PutawayListTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ class PutawayListTable extends BasePageModel {
return new Row(this.page, this.rows.nth(index));
}

rowByOrderNumber(orderNumber: string) {
return new Row(
this.page,
this.rows.filter({
has: this.page.getByTestId('order-number').getByText(orderNumber),
})
);
}

async clickDeleteOrderButton(index: number) {
this.page.once('dialog', (dialog) => dialog.accept());
await this.row(index).deleteOrder.click();
Expand Down
42 changes: 42 additions & 0 deletions src/pages/putaway/putawayDetails/AddCommentToPutawayPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { expect } from '@playwright/test';

import BasePageModel from '@/pages/BasePageModel';

class AddCommentToPutawayPage extends BasePageModel {
async isLoaded() {
await expect(
this.page.getByRole('heading', { name: 'Add Comment' })
).toBeVisible();
}

get commentField() {
return this.page.locator('#comment');
}

get saveButton() {
return this.page.getByRole('button', { name: 'Save' });
}

get recipientDropdown() {
return this.page.locator('#recipient_id_chosen .chosen-single');
Comment thread
kkrawczyk123 marked this conversation as resolved.
Comment thread
kkrawczyk123 marked this conversation as resolved.
}

get recipientOptions() {
return this.page.locator('#recipient_id_chosen .chosen-results li');
Comment thread
kkrawczyk123 marked this conversation as resolved.
Comment thread
kkrawczyk123 marked this conversation as resolved.
}

async selectRecipient(name: string) {
await this.recipientDropdown.click();

await this.recipientOptions.filter({ hasText: name }).click();
}

get senderName() {
return this.page
.locator('tr.prop')
.filter({ hasText: 'From' })
.locator('td.value');
}
}

export default AddCommentToPutawayPage;
17 changes: 17 additions & 0 deletions src/pages/putaway/putawayDetails/PutawayDetailsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import FileHandler from '@/components/FileHandler';
import BasePageModel from '@/pages/BasePageModel';

import AuditingTable from './components/AuditingTable';
import CommentsTable from './components/CommentsTable';
import ItemDetailsTable from './components/ItemDetailsTable';
import ItemStatusTable from './components/ItemStatusTable';
import OrderHeaderTable from './components/OrderHeaderTable';
Expand All @@ -16,6 +17,7 @@ class PutawayDetailsPage extends BasePageModel {
itemDetailsTable: ItemDetailsTable;
auditingTable: AuditingTable;
fileHandler: FileHandler;
commentsTable: CommentsTable;

constructor(page: Page) {
super(page);
Expand All @@ -25,6 +27,7 @@ class PutawayDetailsPage extends BasePageModel {
this.itemDetailsTable = new ItemDetailsTable(page);
this.auditingTable = new AuditingTable(page);
this.fileHandler = new FileHandler(page);
this.commentsTable = new CommentsTable(page);
}

async isLoaded() {
Expand Down Expand Up @@ -127,6 +130,20 @@ class PutawayDetailsPage extends BasePageModel {
this.page.once('dialog', (dialog) => dialog.accept());
await this.actionsDeleteButton.click();
}

get badgeCount() {
return this.page.locator('li.tab-badge');
}

get spinner() {
return this.page.locator('.loading');
}

async waitUntilSpinnerHides() {
await this.spinner.waitFor({
state: 'hidden',
});
}
}

export default PutawayDetailsPage;
72 changes: 72 additions & 0 deletions src/pages/putaway/putawayDetails/components/CommentsTable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { expect, Locator, Page } from '@playwright/test';

import BasePageModel from '@/pages/BasePageModel';

class CommentsTable extends BasePageModel {
constructor(page: Page) {
super(page);
}

async isLoaded() {
await expect(
this.page.getByRole('heading').getByText('Comments')
).toBeVisible();
}

get table() {
return this.page.getByRole('table').filter({
hasText: 'Comment',
});
}

get rows() {
return this.table.getByRole('row');
}

row(index: number) {
return new Row(this.page, this.rows.nth(index));
}

getColumnHeader(columnName: string) {
return this.table.getByRole('row').getByText(columnName, { exact: true });
}

async clickDeleteCommentButton(index: number) {
this.page.once('dialog', (dialog) => dialog.accept());
await this.row(index).deleteButton.click();
}

get emptyCommentTable() {
return this.page.locator('.fade.center.empty').getByText('No comments');
Comment thread
kkrawczyk123 marked this conversation as resolved.
}
}

class Row extends BasePageModel {
row: Locator;
constructor(page: Page, row: Locator) {
super(page);
this.row = row;
}

get comment() {
return this.row.getByRole('cell').nth(2);
}

get recipient() {
return this.row.getByRole('cell').nth(0);
}

get sender() {
return this.row.getByRole('cell').nth(1);
}

get editButton() {
return this.row.getByRole('link', { name: 'Edit', exact: true });
}

get deleteButton() {
return this.row.getByRole('link', { name: 'Delete', exact: true });
}
}

export default CommentsTable;
4 changes: 4 additions & 0 deletions src/pages/putaway/steps/StartStep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class StartStep extends BasePageModel {
async closeDisplayedError() {
return this.page.locator('.alert-close-icon').first().click();
}

get orderNumberValue() {
return this.page.getByTestId('wizardTitle').locator('> div > span').nth(1);
}
}

export default StartStep;
21 changes: 21 additions & 0 deletions src/pages/stockMovementShow/StockMovementShowPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,27 @@ class StockMovementShowPage extends BasePageModel {
this.page.once('dialog', (dialog) => dialog.accept());
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
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] });
}
Comment thread
kkrawczyk123 marked this conversation as resolved.

async openDocumentsTab() {
await expect(async () => {
await this.documentTab.click();
await this.documentsListTable.isLoaded();
}).toPass({ timeout: 20000, intervals: [500, 1000, 2000] });
}
}

export default StockMovementShowPage;
4 changes: 2 additions & 2 deletions src/setup/validateCleanState.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ function assertNoPutawayCandidates(
const details = candidates
.map(
(candidate) =>
`${candidate.product?.productCode ?? '?'} ${candidate.product?.name ?? ''} ` +
`(bin: ${candidate.currentLocation?.name ?? '?'}, qty: ${candidate.quantity ?? '?'}, ` +
`${candidate['product.productCode'] ?? '?'} ${candidate['product.name'] ?? ''} ` +
`(bin: ${candidate['currentLocation.name'] ?? '?'}, qty: ${candidate.quantity ?? '?'}, ` +
`status: ${candidate.putawayStatus ?? '?'})`
)
.join('; ');
Expand Down
Loading
Loading