Skip to content

HP-2382 Migrate PartCreateCest.php Codeception Test to Playwright and remove Legacy Test #185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from 6 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
91 changes: 91 additions & 0 deletions tests/playwright/e2e/manager/part/part-create.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { test } from "@hipanel-core/fixtures";
import {expect} from "@playwright/test";
import PartCreateView from "@hipanel-module-stock/page/PartCreateView";

const partData = {
partno: 'CHASSIS EPYC 7402P',
src_id: 'TEST-DS-01',
dst_id: 'TEST-DS-02',
serials: `MG_TEST_PART${Date.now()}`,
move_descr: 'MG TEST MOVE',
price: 200,
currency: '$',
company_id: 'Other',
};

test.describe('Part Management', () => {
test('Ensure part management buttons work @hipanel-module-stock @manager', async ({ managerPage }) => {
const partView = new PartCreateView(managerPage);
await partView.navigate();

let n = await managerPage.locator('div.item').count();
expect(n).toBe(1);

await partView.addPart();
expect(await managerPage.locator('div.item').count()).toBe(++n);

await partView.addPart();
expect(await managerPage.locator('div.item').count()).toBe(++n);

await partView.copyPart();
expect(await managerPage.locator('div.item').count()).toBe(++n);

await partView.removePart();
expect(await managerPage.locator('div.item').count()).toBe(--n);

await partView.removePart();
expect(await managerPage.locator('div.item').count()).toBe(--n);

await partView.removePart();
expect(await managerPage.locator('div.item').count()).toBe(--n);
});

test('Ensure part cannot be created without data @hipanel-module-stock @manager', async ({ managerPage }) => {
const partView = new PartCreateView(managerPage);
await partView.navigate();
await partView.save();

const errorMessages = [
'Part No. cannot be blank.',
'Source cannot be blank.',
'Destination cannot be blank.',
'Serials cannot be blank.',
'Move description cannot be blank.',
'Purchase price cannot be blank.',
'Currency cannot be blank.',
];

for (const message of errorMessages) {
await expect(managerPage.locator(`text=${message}`)).toBeVisible();
}
});

test('Ensure a part can be created @hipanel-module-stock @manager', async ({ managerPage }) => {
const partView = new PartCreateView(managerPage);
await partView.navigate();
await partView.fillPartFields(partData);
await partView.save();
await expect(managerPage.locator('text=Part has been created')).toBeVisible();
});

test('Ensure multiple parts can be created @hipanel-module-stock @manager', async ({ managerPage }) => {
const partView = new PartCreateView(managerPage);
await partView.navigate();
await partView.fillPartFields(partData);
await partView.addPart();
await partView.save();
await expect(managerPage.locator('text=Part has been created')).toBeVisible();
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Multiple parts creation test needs verification of both parts.

The test adds a second part form but doesn't verify that both parts are actually created.

Enhance the test to verify that both parts are created correctly:

 test('Ensure multiple parts can be created @hipanel-module-stock @manager', async ({ managerPage }) => {
     const partView = new PartCreateView(managerPage);
     await partView.navigate();
+    
+    // Create unique serial numbers for each part to verify later
+    const serial1 = `MG_TEST_PART1_${Date.now()}`;
+    const serial2 = `MG_TEST_PART2_${Date.now()}`;
+    
+    // Fill the first part
+    const firstPartData = { ...partData, serials: serial1 };
+    await partView.fillPartFields(firstPartData);
-    await partView.fillPartFields(partData);
     await partView.addPart();
+    
+    // Fill the second part
+    const secondPartData = { ...partData, serials: serial2 };
+    await partView.fillPartFields(secondPartData, 1); // Assuming second form is at index 1
+    
     await partView.save();
     await expect(managerPage.locator('text=Part has been created')).toBeVisible();
+    
+    // Verify both parts appear in the list
+    await expect(managerPage.locator(`text=${serial1}`)).toBeVisible();
+    await expect(managerPage.locator(`text=${serial2}`)).toBeVisible();
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test('Ensure multiple parts can be created @hipanel-module-stock @manager', async ({ managerPage }) => {
const partView = new PartCreateView(managerPage);
await partView.navigate();
await partView.fillPartFields(partData);
await partView.addPart();
await partView.save();
await expect(managerPage.locator('text=Part has been created')).toBeVisible();
});
test('Ensure multiple parts can be created @hipanel-module-stock @manager', async ({ managerPage }) => {
const partView = new PartCreateView(managerPage);
await partView.navigate();
// Create unique serial numbers for each part to verify later
const serial1 = `MG_TEST_PART1_${Date.now()}`;
const serial2 = `MG_TEST_PART2_${Date.now()}`;
// Fill the first part
const firstPartData = { ...partData, serials: serial1 };
await partView.fillPartFields(firstPartData);
await partView.addPart();
// Fill the second part
const secondPartData = { ...partData, serials: serial2 };
await partView.fillPartFields(secondPartData, 1); // Assuming second form is at index 1
await partView.save();
await expect(managerPage.locator('text=Part has been created')).toBeVisible();
// Verify both parts appear in the list
await expect(managerPage.locator(`text=${serial1}`)).toBeVisible();
await expect(managerPage.locator(`text=${serial2}`)).toBeVisible();
});


test('Ensure a part can be created and then deleted @hipanel-module-stock @manager', async ({ managerPage }) => {
const partView = new PartCreateView(managerPage);
await partView.navigate();
await partView.fillPartFields(partData);
await partView.save();
await expect(managerPage.locator('text=Part has been created')).toBeVisible();

await managerPage.click('text=Delete');
managerPage.on('dialog', async dialog => await dialog.accept());
await expect(managerPage.locator('text=Part has been deleted')).toBeVisible();
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

The dialog handling setup should be before clicking the Delete button.

The current implementation sets up the dialog handler after clicking the delete button, which might lead to race conditions where the dialog appears before the handler is set up.

Move the dialog handler setup before clicking the delete button:

 test('Ensure a part can be created and then deleted @hipanel-module-stock @manager', async ({ managerPage }) => {
     const partView = new PartCreateView(managerPage);
     await partView.navigate();
     await partView.fillPartFields(partData);
     await partView.save();
     await expect(managerPage.locator('text=Part has been created')).toBeVisible();

+    managerPage.on('dialog', async dialog => await dialog.accept());
     await managerPage.click('text=Delete');
-    managerPage.on('dialog', async dialog => await dialog.accept());
     await expect(managerPage.locator('text=Part has been deleted')).toBeVisible();
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test('Ensure a part can be created and then deleted @hipanel-module-stock @manager', async ({ managerPage }) => {
const partView = new PartCreateView(managerPage);
await partView.navigate();
await partView.fillPartFields(partData);
await partView.save();
await expect(managerPage.locator('text=Part has been created')).toBeVisible();
await managerPage.click('text=Delete');
managerPage.on('dialog', async dialog => await dialog.accept());
await expect(managerPage.locator('text=Part has been deleted')).toBeVisible();
});
test('Ensure a part can be created and then deleted @hipanel-module-stock @manager', async ({ managerPage }) => {
const partView = new PartCreateView(managerPage);
await partView.navigate();
await partView.fillPartFields(partData);
await partView.save();
await expect(managerPage.locator('text=Part has been created')).toBeVisible();
managerPage.on('dialog', async dialog => await dialog.accept());
await managerPage.click('text=Delete');
await expect(managerPage.locator('text=Part has been deleted')).toBeVisible();
});

});
31 changes: 31 additions & 0 deletions tests/playwright/e2e/manager/part/part-replace.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { test } from "@hipanel-core/fixtures";
import PartIndexView from "@hipanel-module-stock/page/PartIndexView";

const data = {
filters: [
{
name: "move_descr_ilike",
value: "test description"
},
{
name: "model_types",
value: "cpu"
},
],
replaceData: [
{ serialno: `test${Date.now()}` },
{ serialno: `test${Date.now()}` }
],
};

test.describe("Part Replacement", () => {
test("Ensure parts can be replaced @hipanel-module-stock @manager", async ({ managerPage }) => {
const partIndexView = new PartIndexView(managerPage);

await partIndexView.navigate();
await partIndexView.applyFilters(data.filters);
await partIndexView.selectPartsToReplace(1, data.replaceData.length);
// await partIndexView.fillReplaceForm(data.replaceData, data.rowNumbers);
//await partIndexView.confirmReplacement();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove debug pause and uncomment implementation.

There's a pause() call in the test, which is typically used for debugging and should be removed before merging. Additionally, there are commented-out lines suggesting the test implementation is incomplete.

 await partIndexView.navigate();
 await partIndexView.applyFilters(data.filters);
 await partIndexView.selectPartsToReplace(1, data.replaceData.length);
-await partIndexView.pause();
-// await partIndexView.fillReplaceForm(data.replaceData, data.rowNumbers);
-//await partIndexView.confirmReplacement();
+await partIndexView.fillReplaceForm(data.replaceData, [1, 2]); // Assuming row numbers correspond to the selected range
+await partIndexView.confirmReplacement();

Committable suggestion skipped: line range outside the PR's diff.

});
});
8 changes: 8 additions & 0 deletions tests/playwright/input/PriceWithCurrency.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import InputWithCurrency from "@hipanel-core/input/InputWithCurrency";
import {Page} from "@playwright/test";

export default class PriceWithCurrency extends InputWithCurrency{
static field(page: Page, formId: string, k: number): InputWithCurrency {
return new PriceWithCurrency(page, `${formId}-${k}-price`);
}
}
44 changes: 44 additions & 0 deletions tests/playwright/page/PartCreateView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {Page} from "@playwright/test";
import Select2 from "@hipanel-core/input/Select2";
import PriceWithCurrency from "@hipanel-module-stock/input/PriceWithCurrency";

export default class PartCreateView {
private page: Page;

public constructor(page: Page) {
this.page = page;
}

public async navigate() {
await this.page.goto('/stock/part/create');
}

public async fillPartFields(partData: any) {
await Select2.field(this.page, `select[id$=partno]`).setValue(partData.partno);
await Select2.field(this.page, `select[id$=src_id]`).setValue(partData.src_id);
await Select2.field(this.page, `select[id$=dst_ids]`).setValue(partData.dst_id);

await this.page.fill('input[id$=serials]', partData.serials);
await this.page.fill('input[id$=move_descr]', partData.move_descr);

await PriceWithCurrency.field(this.page, "part", 0).setSumAndCurrency(partData.price, partData.currency);

await this.page.selectOption('select[id$=company_id]', partData.company_id);
}

public async save() {
await this.page.click('button:has-text("Save")');
}

public async addPart() {
await this.page.click("div.item:last-child button.add-item");
}

public async removePart() {
await this.page.click("div.item:last-child button.remove-item");
}

public async copyPart() {
await this.page.click("div.item:last-child button.copy");
}
}
41 changes: 41 additions & 0 deletions tests/playwright/page/PartIndexView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { expect, Page } from "@playwright/test";
import Index from "@hipanel-core/page/Index";

export default class PartIndexView {
private page: Page;
private index: Index;

constructor(page: Page) {
this.page = page;
this.index = new Index(page);
}

async navigate() {
await this.page.goto("/stock/part/index?representation=common");
}

async applyFilters(filters: Array<{ name: string; value: string }>) {
for (const filter of filters) {
await this.index.setFilter(filter.name, filter.value);
}

await this.index.submitSearchButton();
}

public async selectPartsToReplace(start: number, end: number) {
await this.index.chooseRangeOfRowsOnTable(start, end);
await this.page.pause();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove debug pause from selectPartsToReplace method.

The pause() method is typically used for debugging and should be removed before merging to production code.

 public async selectPartsToReplace(start: number, end: number) {
     await this.index.chooseRangeOfRowsOnTable(start, end);
-    await this.page.pause();
     await this.index.clickBulkButton('Replace');
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await this.page.pause();
public async selectPartsToReplace(start: number, end: number) {
await this.index.chooseRangeOfRowsOnTable(start, end);
await this.index.clickBulkButton('Replace');
}

await this.index.clickBulkButton('Replace');
}

public async fillReplaceForm(replaceData: { serialno: string }[], rowNumbers: number[]) {
for (const [index, data] of replaceData.entries()) {
await this.page.fill(`table tbody tr:nth-child(${rowNumbers[index]}) input[name='serialno']`, data.serialno);
}
}

public async confirmReplacement() {
await this.index.clickBulkButton('Peplace');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix typo in button label.

There's a typo in the button label: 'Peplace' instead of 'Replace'. This could cause the test to fail if it's looking for the correct button.

 public async confirmReplacement() {
-    await this.index.clickBulkButton('Peplace');
+    await this.index.clickBulkButton('Replace');
     await this.index.hasNotification('Parts have been replaced');
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await this.index.clickBulkButton('Peplace');
public async confirmReplacement() {
- await this.index.clickBulkButton('Peplace');
+ await this.index.clickBulkButton('Replace');
await this.index.hasNotification('Parts have been replaced');
}

await this.index.hasNotification('Parts have been replaced');
}
}