Skip to content

Commit 7d14b48

Browse files
feat: Refactor lead, organization, person, and quote management tests
- Removed tenantFixtures.ts as it was no longer needed. - Enhanced CoreLocators with additional locators for lead and quote management. - Refactored LeadPage to integrate product creation and improved lead creation logic. - Updated OrganizationPage to include dynamic organization data generation. - Refactored PersonsPage to streamline person creation with organization association. - Enhanced QuotesPage to link quotes with leads and persons dynamically. - Added product management functionality with ProductPage and corresponding tests. - Created product.spec.ts to verify product creation functionality. - Updated lead.spec.ts, organization.spec.ts, persons.spec.ts, and quotes.spec.ts to utilize new data structures and methods.
1 parent 07a038b commit 7d14b48

File tree

14 files changed

+375
-276
lines changed

14 files changed

+375
-276
lines changed

packages/Webkul/Admin/tests/e2e-pw/.state/Admin-auth.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22
"cookies": [
33
{
44
"name": "XSRF-TOKEN",
5-
"value": "eyJpdiI6IlAxRlZJTFYrVzU0enZHRzVmTiswNFE9PSIsInZhbHVlIjoiR3Q0c29taHdqZlBGbytOcVcrYW93U2xPQ01UZWhubldMTmtvRzlPUnJxUm8vYWFPa3MrVU1XUFh4WXNwaSszQ3ZOb005L3RweVIvU1krQWFlTk9vMkFPZzFUU2RrZDlic0NtdW5DZC9FOU5wTUk4YUhBWHl1bWRzV0k4K0ppMzEiLCJtYWMiOiJjOWJlZDIyY2YyN2ViYmFmMmQ0Y2Q4M2RhY2IxODkwMjhkZjkwMWY5MDc0ZDBhNjY1OTY3YTM3YzdiODUxZDA1IiwidGFnIjoiIn0%3D",
5+
"value": "eyJpdiI6ImYxaG1ZQjRHRlBWY2ZMVERBbkd2NFE9PSIsInZhbHVlIjoid1Y0N3B5bkx0UWY4RnN5c05mL0JPMEUxaHhBME1SYy9wSUhkaE1IWFM4SDFVY2NXc2lBTDRIWW9XUk1pVlo4S1RzQlNDTlh0dTlBN3pSZUIxZk9CMjVicnZiN2R1NWRESGtwcVFrQm53NnlYMG5zRlpLTVZtQlp2TThuT3dBYmUiLCJtYWMiOiIxZTk1OTgzNGFmNjAwMDc0ZGUwYzA3MGEzYmQ2NDkxZjZjMDliYzkzM2E1ZWNmMDQ0NjJiY2FhYzUzYzg0ZDEwIiwidGFnIjoiIn0%3D",
66
"domain": "192.168.15.131",
77
"path": "/",
8-
"expires": 1762961415.943007,
8+
"expires": 1763042317.475245,
99
"httpOnly": false,
1010
"secure": false,
1111
"sameSite": "Lax"
1212
},
1313
{
1414
"name": "krayin_crm_session",
15-
"value": "eyJpdiI6IkZZTElQRnRINHBOajJmWFpMZGF5Tnc9PSIsInZhbHVlIjoiS3Z5dWpUOWZ3WU80RUwvcVVpdTR3aTZjcWpZY2sxUGY5ZkxWa0I4OUJ0NC8yV2NXaTFtTnpBalVrOFRBa3RUR0J0VGpIa1ByOVdmTExjVitDa0xYUkluaUxiemxSbFdzYWs2UldMVllhdFVnUlBkUEc0c3REa29SNDNxOXdoRmciLCJtYWMiOiI2YzczMmIwZjhhZjgyODM5NjY5YjIyMjhkNDYxNDEzZGNhMjZiZTBjOThkYmI3MTA5NDc4YTBlMDk5ZTI0ZGE2IiwidGFnIjoiIn0%3D",
15+
"value": "eyJpdiI6IkFqMjVtckcxdkRjRmtqbk0wZVhMN1E9PSIsInZhbHVlIjoidnJWSWRjWUljQ2RBSXQvUk5CWXU3OXZ0L0JjVktzbmxNelZMSVVjTmcrZFpWc1lKcCtXTWNUelZSYStneTl0ZVZkOU1sbUcxYUY1UlVMRURNdGZ1WXdBNmVVclFNOGRqMHlrNHM0L0lnekxmMERLbUQycVFERnZRbHNYMVYwQ2QiLCJtYWMiOiJiMDQ1MGE1ZTQ0YmJiZmNiOGMwNTI1YWY1NGVlMjM2NGY5YzA4YjUyZWFkZGQzNmZkYzkzODlhMzg4YmI2N2I4IiwidGFnIjoiIn0%3D",
1616
"domain": "192.168.15.131",
1717
"path": "/",
18-
"expires": 1762961415.943082,
18+
"expires": 1763042317.475331,
1919
"httpOnly": true,
2020
"secure": false,
2121
"sameSite": "Lax"

packages/Webkul/Admin/tests/e2e-pw/fixtures/tenantFixtures.ts

Lines changed: 0 additions & 64 deletions
This file was deleted.

packages/Webkul/Admin/tests/e2e-pw/locator/CoreLocators.ts

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import { Locator, Page } from "playwright/test";
22

33
type ElementType = "button" | "textbox" | "link";
44
export default class CoreLocators {
5-
readonly page:Page;
5+
readonly page: Page;
66

77

8-
// Person Locators
8+
// Person Locators
99
readonly createPersonLink: Locator;
1010
readonly savePersonButton: Locator;
1111
readonly personNameTextbox: Locator;
@@ -78,6 +78,7 @@ export default class CoreLocators {
7878
readonly productSkuInput: Locator;
7979
readonly leadTitleInput: Locator;
8080
readonly leadValueInput: Locator;
81+
readonly leadProductSelect: Locator;
8182
readonly emailReplyToInput: Locator;
8283
readonly emailSubjectInput: Locator;
8384
readonly fileTitleInput: Locator;
@@ -99,6 +100,9 @@ export default class CoreLocators {
99100
readonly organizationCountryCombobox: Locator;
100101
readonly organizationStateSelect: Locator;
101102

103+
readonly addPersonButton: Locator;
104+
105+
102106
// Textboxes - date or specialized text input
103107
readonly expiredAtTextbox: Locator;
104108
readonly leadExpectedCloseDateInput: Locator;
@@ -136,14 +140,23 @@ export default class CoreLocators {
136140
readonly leadTypeSelect: Locator;
137141
readonly leadUserSelect: Locator;
138142
readonly leadSourceLabelSelect: Locator;
143+
readonly leadOrganizationSelect: Locator;
139144
readonly userRoleSelect: Locator;
140145
readonly userViewPermissionSelect: Locator;
141146
readonly userGroupListbox: Locator;
142147
readonly organizationSelectSearchTextbox: Locator; // For search in org add extra details modal
143-
148+
readonly leadProductAddMoreButton: Locator;
149+
readonly quoteLinkToLeadButton:Locator;
144150
// Search related list item selector
145151
readonly personListItem: (name: string) => Locator;
146152

153+
154+
readonly quoteAddPersonButton:Locator
155+
readonly addAsNewButton:Locator
156+
157+
readonly quoteSelectListPerson:Locator
158+
159+
147160
// Edit and delete icons
148161
readonly firstEditIcon: Locator;
149162
readonly firstDeleteIcon: Locator;
@@ -191,14 +204,23 @@ export default class CoreLocators {
191204
this.createOrganizationButton = page.getByRole('link', { name: 'Create Organization' });
192205
this.saveOrganizationButton = page.getByRole("button", { name: "Save Organization" });
193206
this.deleteButton = page.getByRole('button', { name: 'Delete' });
207+
this.leadProductSelect = page.locator('#products').getByText('Click to Add');
208+
this.leadProductAddMoreButton = page.locator('//button[@class="flex max-w-max items-center gap-2 text-brandColor"]')
209+
this.leadOrganizationSelect = page.locator('div').filter({ hasText: /^Click to add$/ }).nth(2);
210+
211+
this.addPersonButton = page.locator('div', { hasText: /^Click to Add$/ }).nth(1);
194212

213+
this.quoteAddPersonButton= page.locator('.relative.flex.items-center.justify-between').first();
195214
// Links
196215
this.createQuoteLink = page.getByRole("link", { name: "Create Quote" });
197216
this.createProductLink = page.getByRole("link", { name: "Create Product" });
198217
this.createLeadLink = page.getByRole("link", { name: "Create Lead" });
199218
this.signOutLink = page.getByRole("link", { name: "Sign Out" });
200219
this.createOrganizationLink = page.getByRole('link', { name: 'Create Organization' });
201220

221+
this.addAsNewButton = page.getByText('Add as New');
222+
this.quoteSelectListPerson=page.locator(`(//li[@class="flex cursor-pointer gap-2 p-2 transition-colors hover:bg-blue-100 dark:text-gray-300 dark:hover:bg-gray-900"])[1]`);
223+
202224
// Textboxes - single line text input fields
203225
this.subjectTextbox = page.getByRole("textbox", { name: "Subject *" });
204226
this.descriptionTextbox = page.getByRole("textbox", { name: "Description" });
@@ -279,6 +301,8 @@ export default class CoreLocators {
279301
this.firstEditIcon = page.locator("span.cursor-pointer.icon-edit").first();
280302
this.firstDeleteIcon = page.locator("span.cursor-pointer.icon-delete").first();
281303

304+
this.quoteLinkToLeadButton=page.locator('div:nth-child(2) > div > .relative.inline-block > .relative');
305+
282306
// Activity modal selectors
283307
this.addActivityButton = page.getByRole("button", { name: " Activity" });
284308
this.activityCallOption = page.getByText("Call", { exact: true });
@@ -295,7 +319,7 @@ export default class CoreLocators {
295319

296320
// Organization Locators Initialization
297321
this.createOrgLink = page.getByRole('link', { name: 'Create Organization' });
298-
322+
299323

300324
this.orgNameTextbox = page.getByRole('textbox', { name: 'Name *' });
301325
this.orgAddressTextarea = page.locator('textarea[name="address\\[address\\]"]');
@@ -307,7 +331,7 @@ export default class CoreLocators {
307331
this.orgExtraDetailsDiv = page.locator('div').filter({ hasText: /^Click to add$/ });
308332
this.orgExampleListItem = (text: string) => page.getByRole('listitem').filter({ hasText: text });
309333

310-
// Person Locators Initialization
334+
// Person Locators Initialization
311335
this.createPersonLink = page.getByRole('link', { name: 'Create Person' });
312336
this.savePersonButton = page.getByRole('button', { name: 'Save Person' });
313337
this.personNameTextbox = page.getByRole('textbox', { name: 'Name *' });
@@ -327,12 +351,11 @@ export default class CoreLocators {
327351

328352
async getElementByTypeAndName(type: ElementType, name: string) {
329353

330-
return this.page.getByRole(`${type}`, { name: `${name}`, exact: true })
354+
return this.page.getByRole(`${type}`, { name: `${name}`,exact:true});
331355

332356
}
333-
async selectListItmeByName(value:string)
334-
{
335-
return this.page.getByRole('listitem').filter({ hasText: `${value}` });
357+
async selectListItmeByName(value: string) {
358+
return this.page.getByRole('listitem').filter({ hasText: `${value}` });
336359
}
337360

338361

packages/Webkul/Admin/tests/e2e-pw/pages/leads/LeadPage.ts

Lines changed: 63 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
11
import { Page, Locator, expect } from "@playwright/test";
22
import CoreLocators from "../../locator/CoreLocators";
3-
import { PersonData } from "../persons/PersonsPage";
3+
import { personData, PersonData } from "../persons/PersonsPage";
4+
import { productData, ProductData, ProductPage } from "../products/ProductPage";
5+
import { generateDescription, generateName } from "../../utils/faker";
6+
7+
48
export type LeadData = {
5-
title: string,
6-
description: string,
7-
email:string,
8-
phone: string,
9-
person:PersonData,
9+
title: string;
10+
description: string;
11+
value: string;
12+
expectedCloseDate: string; // ISO date string
13+
person: PersonData;
14+
organizationName: string;
15+
product: ProductData;
16+
};
17+
18+
export const leadData:LeadData = {
19+
title: generateName(),
20+
description: generateDescription(),
21+
value: (Math.floor(Math.random()*10000)).toString(),
22+
expectedCloseDate:"2028-12-31",
23+
person:personData,
24+
product:productData,
25+
organizationName:personData.organizationName
1026
};
27+
1128
export class LeadPage extends CoreLocators {
1229
readonly page: Page;
1330

@@ -19,9 +36,9 @@ export class LeadPage extends CoreLocators {
1936
readonly typeDropdown: Locator;
2037
readonly userDropdown: Locator;
2138
readonly leadValueInput: Locator;
22-
readonly addPersonButton: Locator;
39+
2340
readonly personSearchInput: Locator;
24-
readonly addAsNewButton: Locator;
41+
2542
readonly personEmailInput: Locator;
2643
readonly personPhoneInput: Locator;
2744
readonly addOrganizationButton: Locator;
@@ -32,9 +49,9 @@ export class LeadPage extends CoreLocators {
3249
readonly leadSuccessToast: Locator;
3350
readonly listViewButton: Locator;
3451
readonly agreeButton: Locator;
35-
readonly editLeadButton:Locator;
36-
readonly deleteLeadButton:Locator;
37-
readonly listSearchInput:Locator;
52+
readonly editLeadButton: Locator;
53+
readonly deleteLeadButton: Locator;
54+
readonly listSearchInput: Locator;
3855

3956
// ---- Lead Tabs Locators ----
4057
readonly mailButton: Locator;
@@ -69,7 +86,7 @@ export class LeadPage extends CoreLocators {
6986
readonly createLeadButton: Locator;
7087
readonly searchInput: Locator;
7188
// ------ Validation Message
72-
readonly expectedCloseDateMustBeDateAfter:Locator
89+
readonly expectedCloseDateMustBeDateAfter: Locator
7390

7491

7592

@@ -90,12 +107,12 @@ export class LeadPage extends CoreLocators {
90107
this.userDropdown = page.locator('select[name="user_id"]');
91108
this.leadValueInput = page.locator('input[name="lead_value"]');
92109
this.searchInput = page.getByRole('textbox', { name: 'Search by Title' });
93-
this.listSearchInput=page.getByRole('textbox',{name:'Search'})
110+
this.listSearchInput = page.getByRole('textbox', { name: 'Search' })
94111

95112
// Add person
96-
this.addPersonButton = page.locator('div', { hasText: /^Click to Add$/ }).nth(1);
113+
97114
this.personSearchInput = page.getByRole('textbox', { name: 'Search...' });
98-
this.addAsNewButton = page.getByText('Add as New');
115+
99116
this.personEmailInput = page.locator('input[name="person[emails][0][value]"]');
100117
this.personPhoneInput = page.locator('input[name="person[contact_numbers][0][value]"]');
101118

@@ -110,7 +127,7 @@ export class LeadPage extends CoreLocators {
110127
this.editLeadButton = page.getByRole('link', { name: '' }).first();
111128
this.listViewButton = page.getByRole('link', { name: '' });
112129
this.agreeButton = page.getByRole('button', { name: 'Agree', exact: true });
113-
this.deleteLeadButton= page.locator('.cursor-pointer.rounded-md.p-1\\.5.text-2xl.transition-all.hover\\:bg-gray-200.dark\\:hover\\:bg-gray-800.max-sm\\:place-self-center.icon-delete').first();
130+
this.deleteLeadButton = page.locator('.cursor-pointer.rounded-md.p-1\\.5.text-2xl.transition-all.hover\\:bg-gray-200.dark\\:hover\\:bg-gray-800.max-sm\\:place-self-center.icon-delete').first();
114131

115132

116133
// Tabs
@@ -146,47 +163,58 @@ export class LeadPage extends CoreLocators {
146163

147164
// validation message
148165

149-
this.expectedCloseDateMustBeDateAfter=page.getByText('The expected close date must be a date after');
166+
this.expectedCloseDateMustBeDateAfter = page.getByText('The expected close date must be a date after');
150167
}
151168
async navigateToLeadList() {
152169
await this.page.goto("admin/leads");
153170
}
154-
async getLeadByTitle(title:string)
155-
{
171+
async getLeadByTitle(title: string) {
156172
return this.page.getByRole('link', { name: ` ${title}` });
157173
}
158-
async createLead(leadData:LeadData)
159-
{
174+
async createLead(leadData: LeadData) {
175+
const productPage = new ProductPage(this.page);
176+
await productPage.createProduct(leadData.product);
160177

161178
await this.navigateToLeadList();
162-
163179
await this.createLeadButton.click();
164180

165181
await this.titleInput.fill(leadData.title);
166182
await this.descriptionTextarea.fill(leadData.description);
167183
await this.sourceDropdown.selectOption("1");
168184
await this.typeDropdown.selectOption("1");
169185
await this.userDropdown.selectOption("1");
170-
await this.leadValueInput.fill("1000");
186+
await this.leadValueInput.fill(leadData.value);
171187

172188
await this.addPersonButton.click();
173189
await this.personSearchInput.fill(leadData.person.name);
174-
await this.selectListItmeByName(leadData.person.name);
175-
await this.personEmailInput.fill(leadData.email);
176-
await this.personPhoneInput.fill(leadData.phone);
177-
178-
await this.addOrganizationButton.click();
179-
await this.organizationSearchInput.fill(leadData.title);
180-
await this.addAsNewButton.click();
181-
182-
183-
184-
(await this.getElementByTypeAndName('button',"Save")).click();
190+
const personItem = (await this.selectListItmeByName(leadData.person.name)).first();
191+
await this.page.waitForTimeout(1000);
192+
const isPersonAlreadyPresent = await personItem.isVisible();
193+
194+
if (isPersonAlreadyPresent) {
195+
await personItem.click();
196+
console.log("person allready present");
197+
}
198+
else {
199+
200+
await this.addAsNewButton.click();
201+
await this.personEmailInput.fill(leadData.person.emails);
202+
await this.personPhoneInput.fill(leadData.person.contactNumber);
203+
await this.addOrganizationButton.click(); // this an issue add organiztion is not working if person allready present so that i have added this into else condition.
204+
await this.organizationSearchInput.fill(leadData.title);
205+
await this.addAsNewButton.click();
206+
207+
}
208+
await this.leadProductAddMoreButton.click();
209+
await this.leadProductSelect.click();
210+
(await this.getElementByTypeAndName('textbox','Search...')).fill(leadData.product.name);
211+
await this.page.locator(`//li[@class="cursor-pointer px-4 py-2 text-gray-800 transition-colors hover:bg-blue-100 dark:text-white dark:hover:bg-gray-900"]`).first().click();
212+
(await this.getElementByTypeAndName('button', "Save")).click();
185213
await this.searchInput.fill(leadData.title);
186214
await this.page.keyboard.press('Enter');
187215
await expect((await this.getLeadByTitle(leadData.title))).toBeVisible();
188216

189-
217+
190218
await expect(this.leadSuccessToast).toBeVisible();
191219

192220
}

0 commit comments

Comments
 (0)