Skip to content

Commit 6e56ee8

Browse files
authored
Merge pull request #69 from openboxes/OBPIH-7535
OBPIH-7535 Putaway - assert attempt to edit completed putaway
2 parents f00d68a + 59551d7 commit 6e56ee8

File tree

7 files changed

+339
-3
lines changed

7 files changed

+339
-3
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { expect, Page } from '@playwright/test';
2+
3+
import BasePageModel from '@/pages/BasePageModel';
4+
5+
import SplitModalTable from './SplitModalTable';
6+
7+
class SplitModal extends BasePageModel {
8+
table: SplitModalTable;
9+
10+
constructor(page: Page) {
11+
super(page);
12+
this.table = new SplitModalTable(page);
13+
}
14+
15+
get modal() {
16+
return this.page.locator('.ReactModal__Content');
17+
}
18+
19+
async isLoaded() {
20+
await expect(this.modal).toBeVisible();
21+
}
22+
23+
get saveButton() {
24+
return this.modal.getByTestId('save-button');
25+
}
26+
27+
get cancelButton() {
28+
return this.modal.getByTestId('cancel-button');
29+
}
30+
31+
get addLineButton() {
32+
return this.modal.getByTestId('add-line-button');
33+
}
34+
}
35+
36+
export default SplitModal;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { Locator, Page } from '@playwright/test';
2+
3+
import BasePageModel from '@/pages/BasePageModel';
4+
5+
class SplitModalTable extends BasePageModel {
6+
constructor(page: Page) {
7+
super(page);
8+
}
9+
10+
get table() {
11+
return this.page.getByRole('table');
12+
}
13+
14+
get rows() {
15+
return this.table.getByRole('row');
16+
}
17+
18+
row(index: number) {
19+
return new Row(this.page, this.rows.nth(index));
20+
}
21+
}
22+
23+
class Row extends BasePageModel {
24+
row: Locator;
25+
26+
constructor(page: Page, row: Locator) {
27+
super(page);
28+
this.row = row;
29+
}
30+
31+
get deleteButton() {
32+
return this.row.getByTestId('delete-button');
33+
}
34+
35+
async getPutawayBin(putawayBin: string) {
36+
await this.row
37+
.getByTestId('bin-select')
38+
.getByRole('textbox')
39+
.fill(putawayBin);
40+
await this.page
41+
.getByTestId('custom-select-dropdown-menu')
42+
.locator('.react-select__option')
43+
.nth(0)
44+
.click();
45+
}
46+
47+
get quantityField() {
48+
return this.row.getByRole('cell').getByTestId('quantity-input');
49+
}
50+
}
51+
52+
export default SplitModalTable;

src/pages/putaway/components/StartPutawayTable.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class Row extends BasePageModel {
3333
}
3434

3535
get splitLineButton() {
36-
return this.row.getByRole('button', { name: 'Split line' });
36+
return this.row.getByTestId('open-modal');
3737
}
3838

3939
get deleteButton() {
@@ -58,6 +58,10 @@ class Row extends BasePageModel {
5858
getCurrentBin(currentBin: string) {
5959
return this.row.getByTestId('cell-0-currentBin').getByText(currentBin);
6060
}
61+
62+
get quantityField() {
63+
return this.row.getByTestId('cell-0-quantity').getByRole('spinbutton');
64+
}
6165
}
6266

6367
export default StartPutawayTable;

src/pages/putaway/list/PutawayListTable.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ class PutawayListTable extends BasePageModel {
3131
this.page.once('dialog', (dialog) => dialog.accept());
3232
await this.deleteOrderButton.click();
3333
}
34+
35+
get emptyPutawayList() {
36+
return this.table
37+
.locator('.empty')
38+
.getByText('No orders match the given criteria');
39+
}
3440
}
3541

3642
class Row extends BasePageModel {

src/pages/putaway/putawayDetails/PutawayDetailsPage.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,16 @@ class PutawayDetailsPage extends BasePageModel {
113113
get generatePutawayListButton() {
114114
return this.page.getByRole('link', { name: 'Generate Putaway List' });
115115
}
116+
117+
async assertClickOnEditButtonWhenPutawayCompleted() {
118+
this.page.once('dialog', (dialog) => {
119+
expect(dialog.message()).toContain(
120+
'This feature is not available for completed and canceled putaways'
121+
);
122+
dialog.accept();
123+
});
124+
await this.editButton.click();
125+
}
116126
}
117127

118128
export default PutawayDetailsPage;

src/pages/putaway/steps/StartStep.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import { expect, Page } from '@playwright/test';
22

33
import BasePageModel from '@/pages/BasePageModel';
4-
5-
import StartPutawayTable from '../components/StartPutawayTable';
4+
import SplitModal from '@/pages/putaway/components/SplitModal';
5+
import StartPutawayTable from '@/pages/putaway/components/StartPutawayTable';
66

77
class StartStep extends BasePageModel {
88
table: StartPutawayTable;
9+
splitModal: SplitModal;
910

1011
constructor(page: Page) {
1112
super(page);
1213
this.table = new StartPutawayTable(page);
14+
this.splitModal = new SplitModal(page);
1315
}
1416

1517
async isLoaded() {
@@ -23,6 +25,30 @@ class StartStep extends BasePageModel {
2325
get saveButton() {
2426
return this.page.getByTestId('save-button');
2527
}
28+
29+
get generatePutawayListButton() {
30+
return this.page.getByTestId('export-button');
31+
}
32+
33+
get sortByCurrentBinButton() {
34+
return this.page.getByTestId('sort-button');
35+
}
36+
37+
get validationOnEditCompletedPutaway() {
38+
return this.page
39+
.locator('[class*="alert"]')
40+
.getByText(/Can't update completed putaway/);
41+
}
42+
43+
get validationOnDeleteItemFromCompletedPutaway() {
44+
return this.page
45+
.locator('[class*="alert"]')
46+
.getByText(/Can't remove an item on completed putaway/);
47+
}
48+
49+
async closeDisplayedError() {
50+
return this.page.locator('.alert-close-icon').click();
51+
}
2652
}
2753

2854
export default StartStep;
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
import AppConfig from '@/config/AppConfig';
2+
import { ShipmentType } from '@/constants/ShipmentType';
3+
import { expect, test } from '@/fixtures/fixtures';
4+
import { StockMovementResponse } from '@/types';
5+
import { getShipmentId, getShipmentItemId } from '@/utils/shipmentUtils';
6+
7+
test.describe('Assert attempt to edit completed putaway', () => {
8+
let STOCK_MOVEMENT: StockMovementResponse;
9+
10+
test.beforeEach(
11+
async ({
12+
supplierLocationService,
13+
stockMovementService,
14+
fifthProductService,
15+
receivingService,
16+
}) => {
17+
const supplierLocation = await supplierLocationService.getLocation();
18+
STOCK_MOVEMENT = await stockMovementService.createInbound({
19+
originId: supplierLocation.id,
20+
});
21+
22+
const product = await fifthProductService.getProduct();
23+
24+
await stockMovementService.addItemsToInboundStockMovement(
25+
STOCK_MOVEMENT.id,
26+
[{ productId: product.id, quantity: 10 }]
27+
);
28+
29+
await stockMovementService.sendInboundStockMovement(STOCK_MOVEMENT.id, {
30+
shipmentType: ShipmentType.AIR,
31+
});
32+
33+
const { data: stockMovement } =
34+
await stockMovementService.getStockMovement(STOCK_MOVEMENT.id);
35+
const shipmentId = getShipmentId(stockMovement);
36+
const { data: receipt } = await receivingService.getReceipt(shipmentId);
37+
const receivingBin =
38+
AppConfig.instance.receivingBinPrefix + STOCK_MOVEMENT.identifier;
39+
40+
await receivingService.createReceivingBin(shipmentId, receipt);
41+
42+
await receivingService.updateReceivingItems(shipmentId, [
43+
{
44+
shipmentItemId: getShipmentItemId(receipt, 0, 0),
45+
quantityReceiving: 10,
46+
binLocationName: receivingBin,
47+
},
48+
]);
49+
await receivingService.completeReceipt(shipmentId);
50+
}
51+
);
52+
53+
test.afterEach(
54+
async ({
55+
stockMovementShowPage,
56+
stockMovementService,
57+
navbar,
58+
transactionListPage,
59+
oldViewShipmentPage,
60+
}) => {
61+
await navbar.configurationButton.click();
62+
await navbar.transactions.click();
63+
await transactionListPage.table.row(1).actionsButton.click();
64+
await transactionListPage.table.deleteButton.click();
65+
await expect(transactionListPage.successMessage).toBeVisible();
66+
await transactionListPage.table.row(1).actionsButton.click();
67+
await transactionListPage.table.deleteButton.click();
68+
await expect(transactionListPage.successMessage).toBeVisible();
69+
70+
await stockMovementShowPage.goToPage(STOCK_MOVEMENT.id);
71+
await stockMovementShowPage.detailsListTable.oldViewShipmentPage.click();
72+
await oldViewShipmentPage.undoStatusChangeButton.click();
73+
await stockMovementShowPage.isLoaded();
74+
await stockMovementShowPage.rollbackButton.click();
75+
76+
await stockMovementService.deleteStockMovement(STOCK_MOVEMENT.id);
77+
}
78+
);
79+
80+
test('Assert attempt to edit completed putaway', async ({
81+
stockMovementShowPage,
82+
navbar,
83+
createPutawayPage,
84+
internalLocationService,
85+
putawayDetailsPage,
86+
putawayListPage,
87+
page,
88+
}) => {
89+
await test.step('Go to create putaway page', async () => {
90+
await stockMovementShowPage.goToPage(STOCK_MOVEMENT.id);
91+
await stockMovementShowPage.isLoaded();
92+
await navbar.profileButton.click();
93+
await navbar.refreshCachesButton.click();
94+
await navbar.inbound.click();
95+
await navbar.createPutaway.click();
96+
await createPutawayPage.isLoaded();
97+
});
98+
99+
await test.step('Start putaway', async () => {
100+
await createPutawayPage.table.row(0).checkbox.click();
101+
await createPutawayPage.startPutawayButton.click();
102+
await createPutawayPage.startStep.isLoaded();
103+
});
104+
105+
await test.step('Select bin to putaway', async () => {
106+
const internalLocation = await internalLocationService.getLocation();
107+
await createPutawayPage.startStep.table.row(0).putawayBinSelect.click();
108+
await createPutawayPage.startStep.table
109+
.row(0)
110+
.getPutawayBin(internalLocation.name)
111+
.click();
112+
await createPutawayPage.startStep.nextButton.click();
113+
});
114+
115+
await test.step('Go to next page and complete putaway', async () => {
116+
await createPutawayPage.completeStep.isLoaded();
117+
await createPutawayPage.completeStep.completePutawayButton.click();
118+
});
119+
120+
await test.step('Assert completing putaway', async () => {
121+
await putawayDetailsPage.isLoaded();
122+
await expect(putawayDetailsPage.statusTag).toHaveText('Completed');
123+
});
124+
125+
await test.step('Assert try to edit completed putaway', async () => {
126+
await putawayDetailsPage.assertClickOnEditButtonWhenPutawayCompleted();
127+
});
128+
129+
await test.step('Assert delete button is not visible for completed putaway', async () => {
130+
await putawayDetailsPage.summaryActionsButton.click();
131+
await expect(putawayDetailsPage.actionsDeleteButton).toBeHidden();
132+
});
133+
134+
await test.step('Go backward in browser', async () => {
135+
await page.goBack();
136+
await createPutawayPage.startStep.isLoaded();
137+
});
138+
139+
await test.step('Assert attemps to edit in completed putaway', async () => {
140+
await createPutawayPage.startStep.saveButton.click();
141+
await expect(
142+
createPutawayPage.startStep.validationOnEditCompletedPutaway
143+
).toBeVisible();
144+
await createPutawayPage.startStep.closeDisplayedError();
145+
await createPutawayPage.startStep.nextButton.click();
146+
await expect(
147+
createPutawayPage.startStep.validationOnEditCompletedPutaway
148+
).toBeVisible();
149+
await createPutawayPage.startStep.closeDisplayedError();
150+
await createPutawayPage.startStep.generatePutawayListButton.click();
151+
await expect(
152+
createPutawayPage.startStep.validationOnEditCompletedPutaway
153+
).toBeVisible();
154+
await createPutawayPage.startStep.closeDisplayedError();
155+
await createPutawayPage.startStep.sortByCurrentBinButton.click();
156+
await expect(
157+
createPutawayPage.startStep.validationOnEditCompletedPutaway
158+
).toBeVisible();
159+
await createPutawayPage.startStep.closeDisplayedError();
160+
});
161+
162+
await test.step('Assert attemps to edit item in completed putaway', async () => {
163+
await createPutawayPage.startStep.isLoaded();
164+
await createPutawayPage.startStep.table.row(0).deleteButton.click();
165+
await expect(
166+
createPutawayPage.startStep.validationOnDeleteItemFromCompletedPutaway
167+
).toBeVisible();
168+
await createPutawayPage.startStep.closeDisplayedError();
169+
await createPutawayPage.startStep.table.row(0).splitLineButton.click();
170+
await createPutawayPage.startStep.splitModal.isLoaded();
171+
await createPutawayPage.startStep.splitModal.addLineButton.click();
172+
const internalLocation = await internalLocationService.getLocation();
173+
await createPutawayPage.startStep.splitModal.table
174+
.row(1)
175+
.getPutawayBin(internalLocation.name);
176+
await createPutawayPage.startStep.splitModal.table
177+
.row(1)
178+
.quantityField.fill('5');
179+
await createPutawayPage.startStep.splitModal.table
180+
.row(2)
181+
.getPutawayBin(internalLocation.name);
182+
await createPutawayPage.startStep.splitModal.table
183+
.row(2)
184+
.quantityField.fill('5');
185+
await createPutawayPage.startStep.splitModal.saveButton.click();
186+
await expect(
187+
createPutawayPage.startStep.validationOnEditCompletedPutaway
188+
).toBeVisible();
189+
await createPutawayPage.startStep.closeDisplayedError();
190+
await createPutawayPage.startStep.table.row(0).editButton.click();
191+
await createPutawayPage.startStep.table.row(0).quantityField.fill('20');
192+
await expect(createPutawayPage.startStep.nextButton).toBeDisabled();
193+
await expect(createPutawayPage.startStep.saveButton).toBeDisabled();
194+
});
195+
196+
await test.step('Go putaway list page and assert pending putaway is not created', async () => {
197+
await putawayListPage.goToPage();
198+
await putawayListPage.isLoaded();
199+
await putawayListPage.emptyPutawayList.isVisible();
200+
});
201+
});
202+
});

0 commit comments

Comments
 (0)