Skip to content

Commit 7534ef4

Browse files
feat: Implement campaign management functionalities including creation, editing, and deletion; enhance event management tests
1 parent 9e8d38d commit 7534ef4

File tree

6 files changed

+196
-32
lines changed

6 files changed

+196
-32
lines changed

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { LegacyCharacterEncoding } from "crypto";
12
import { Locator, Page } from "playwright/test";
23

34
type ElementType = "button" | "textbox" | "link";
@@ -156,6 +157,8 @@ export default class CoreLocators {
156157
// Edit and delete icons
157158
readonly firstEditIcon: Locator;
158159
readonly firstDeleteIcon: Locator;
160+
// Multi select checkbox
161+
readonly multiSelectCheckbox:Locator;
159162

160163
// Activity modal selectors
161164
readonly addActivityButton: Locator;
@@ -197,7 +200,7 @@ export default class CoreLocators {
197200
readonly editLeadButton: Locator;
198201
readonly listViewButton: Locator;
199202
readonly deleteLeadButton: Locator;
200-
203+
readonly noRecordsAvailable:Locator
201204
// Tabs
202205
readonly mailButton: Locator;
203206
readonly fileButton: Locator;
@@ -225,6 +228,7 @@ export default class CoreLocators {
225228
readonly expectedCloseDateMustBeDateAfter: Locator;
226229

227230

231+
228232
// Other
229233
readonly appLocator: Locator;
230234

@@ -308,6 +312,8 @@ export default class CoreLocators {
308312
this.activityScheduleToInput = page.locator('input[name="schedule_to"]');
309313
this.eventDateInput = page.locator('input[name="date"]');
310314

315+
this.noRecordsAvailable = page.getByText('No Records Available.')
316+
311317
// Textareas - multi-line input fields
312318
this.billingAddressTextarea = page.locator('textarea[name="billing_address\\[address\\]"]');
313319
this.shippingAddressTextarea = page.locator('textarea[name="shipping_address\\[address\\]"]');
@@ -350,6 +356,9 @@ export default class CoreLocators {
350356
this.firstEditIcon = page.locator("span.cursor-pointer.icon-edit").first();
351357
this.firstDeleteIcon = page.locator("span.cursor-pointer.icon-delete").first();
352358

359+
//mass delte checkbox
360+
this.multiSelectCheckbox= page.locator('.icon-checkbox-outline').first();
361+
353362
this.quoteLinkToLeadButton = page.locator('div:nth-child(2) > div > .relative.inline-block > .relative');
354363

355364
// Activity modal selectors
@@ -461,6 +470,11 @@ export default class CoreLocators {
461470
// Other
462471
this.appLocator = page.locator("#app");
463472
}
473+
async searchByName(name:string)
474+
{
475+
(await this.getElementByTypeAndName('textbox','Search')).fill(name);
476+
await this.page.keyboard.press('Enter');
477+
}
464478

465479
async getElementByTypeAndName(type: ElementType, name: string) {
466480
return this.page.getByRole(`${type}`, { name: `${name}`, exact: true });

packages/Webkul/Admin/tests/e2e-pw/pages/settings/SettingsPage.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ export class SettingsPage extends CoreLocators {
2626

2727
// Email Templates
2828
async navigateToEmailTemplates() {
29-
await this.page.goto("admin/settings/email-templates");
29+
await this.page.goto("admin/settings/marketing/email-templates");
3030
}
3131

3232
// Events
3333
async navigateToEvents() {
34-
await this.page.goto("admin/settings/events");
34+
await this.page.goto("admin/settings/marketing/events");
3535
}
3636

3737
// Campaigns
3838
async navigateToCampaigns() {
39-
await this.page.goto("admin/settings/campaigns");
39+
await this.page.goto("admin/settings/marketing/campaigns");
4040
}
4141

4242
// Webhooks
Lines changed: 103 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,113 @@
1-
import { Page } from "playwright/test";
2-
import { SettingsPage } from "../SettingsPage";
1+
import { Page, Locator, expect } from '@playwright/test';
2+
import { generateFullName, generateLastName, generateRandomNumericString } from '../../../utils/faker';
3+
import { SettingsPage } from '../SettingsPage';
4+
import { eventdata, EventData } from './EventsPage';
35

4-
export class CampaignsPage extends SettingsPage {
6+
export type CampaignData = {
7+
name: string;
8+
subject: string;
9+
emailTemplateId: string ;
10+
event:EventData ;
11+
active: number;
12+
}
13+
export const campaignData:CampaignData={
14+
name:generateFullName(),
15+
subject:generateLastName(),
16+
emailTemplateId:generateRandomNumericString(),
17+
event:eventdata,
18+
active:1,
19+
}
20+
21+
export class CampaignsPage extends SettingsPage{
522
readonly page: Page;
623

24+
// Campaign locators
25+
readonly createCampaignButton: Locator;
26+
readonly campaignNameInput: Locator;
27+
readonly campaignSubjectInput: Locator;
28+
readonly emailTemplateDropdown: Locator;
29+
readonly eventDropdown: Locator;
30+
readonly activeToggle: Locator;
31+
readonly saveCampaignButton: Locator;
32+
readonly firstCampaignEditButton: Locator;
33+
readonly firstCampaignDeleteButton: Locator;
34+
readonly confirmDeleteButton: Locator;
35+
readonly successCreatedMessage: Locator;
36+
readonly successUpdatedMessage:Locator;
37+
readonly successDeletedMessage:Locator;
38+
739
constructor(page: Page) {
840
super(page);
941
this.page = page;
42+
43+
this.createCampaignButton = page.getByRole('button', { name: 'Create Campaigns' })
44+
this.campaignNameInput = page.locator('input[name="name"]');
45+
this.campaignSubjectInput = page.getByRole('textbox', { name: 'Subject *' });
46+
this.emailTemplateDropdown = page.locator('#marketing_template_id');
47+
this.eventDropdown = page.getByLabel('Event');
48+
this.activeToggle = page.locator('.peer.h-5');
49+
this.saveCampaignButton = page.getByRole('button', { name: 'Save Activity' });
50+
51+
this.firstCampaignEditButton = page.locator('.row > div:nth-child(6) > a').first();
52+
this.firstCampaignDeleteButton = page.locator('xpath=(//span[contains(@class, "icon-delete")])[1]');
53+
this.confirmDeleteButton = page.getByRole('button', { name: 'Agree', exact: true });
54+
55+
this.successCreatedMessage = page.getByText(/(created) successfully\./).first();
56+
this.successUpdatedMessage= page.getByText(/(updated) successfully\./).first();
57+
this.successDeletedMessage= page.getByText(/(deleted) successfully\./).first();
58+
}
59+
60+
async gotoCampaigns() {
61+
await this.page.goto("admin/settings/marketing/campaigns");
1062
}
1163

64+
async createCampaign(data: CampaignData) {
65+
await this.createCampaignButton.click();
66+
await this.campaignNameInput.fill(data.name);
67+
await this.campaignSubjectInput.fill(data.subject);
68+
await this.campaignSubjectInput.click(); // For validation if needed
69+
await this.campaignSubjectInput.fill(data.subject);
70+
71+
await this.eventDropdown.selectOption({label:data.event.name});
72+
await this.emailTemplateDropdown.selectOption({value:"1"});
73+
1274

75+
if (data.active) {
76+
// Only toggle if not already active, this might require check logic per app specifics
77+
await this.activeToggle.click();
78+
}
79+
80+
await this.saveCampaignButton.click();
81+
await expect(this.successCreatedMessage).toBeVisible();
82+
await this.searchByName(data.name);
83+
await expect(this.page.getByText(data.name).first()).toBeVisible();
84+
}
85+
86+
async editCampaign(data: CampaignData) {
87+
await this.firstCampaignEditButton.click();
88+
await this.campaignNameInput.fill(data.name);
89+
await this.campaignSubjectInput.fill(data.subject);
90+
await this.campaignSubjectInput.click(); // For validation if needed
91+
await this.campaignSubjectInput.fill(data.subject);
92+
93+
await this.eventDropdown.selectOption({label:data.event.name});
94+
await this.emailTemplateDropdown.selectOption({value:"1"});
95+
96+
97+
if (data.active) {
98+
// Only toggle if not already active, this might require check logic per app specifics
99+
await this.activeToggle.click();
100+
}
101+
102+
await this.saveCampaignButton.click();
103+
await expect(this.successUpdatedMessage).toBeVisible();
104+
await this.searchByName(data.name);
105+
await expect(this.page.getByText(data.name).first()).toBeVisible();
106+
}
107+
108+
async deleteCampaign() {
109+
await this.firstCampaignDeleteButton.click();
110+
await this.confirmDeleteButton.click();
111+
await expect(this.successDeletedMessage).toBeVisible();
112+
}
13113
}

packages/Webkul/Admin/tests/e2e-pw/pages/settings/settings-pages/EventsPage.ts

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ import { Page, Locator, expect } from '@playwright/test';
22
import { SettingsPage } from '../SettingsPage';
33
import { generateDescription, generateFullName, generateRandomDateTime } from '../../../utils/faker';
44

5-
type EventData={
6-
name:string,
7-
description:string,
8-
date:string
5+
export type EventData = {
6+
name: string,
7+
description: string,
8+
date: string
99
}
10-
export const eventdata:EventData={
11-
name:generateFullName(),
12-
description:generateDescription(),
13-
date:"2025-11-18",
10+
export const eventdata: EventData = {
11+
name: generateFullName(),
12+
description: generateDescription(),
13+
date: "2027-11-18",
1414
}
1515

1616
export class EventsPage extends SettingsPage {
@@ -39,26 +39,42 @@ export class EventsPage extends SettingsPage {
3939
this.successMessage = page.getByText(/Event (created|updated|deleted) successfully./);
4040
}
4141

42-
async gotoEventsPage() {
43-
await this.page.goto('admin/settings/marketing/events');
44-
}
42+
async createEvent(eventdata: EventData) {
4543

46-
async openCreateEventModal() {
4744
await this.createEventButton.click();
45+
await this.nameInput.fill(eventdata.name);
46+
await this.descriptionTextarea.fill(eventdata.name);
47+
await this.dateInput.fill(eventdata.date);
48+
await this.saveEventButton.click();
49+
await expect(this.successMessage).toBeVisible();
50+
4851
}
52+
async massDeleteEvents()
53+
{
54+
await this.multiSelectCheckbox.click()
55+
await this.deleteButton.click();
56+
await this.agreeButton.click();
57+
await expect(this.noRecordsAvailable).toBeVisible();
4958

50-
async createEvent(eventdata:EventData) {
59+
}
60+
async editEvents(eventData:EventData)
61+
{
62+
63+
await this.firstEditIcon.click();
5164
await this.nameInput.fill(eventdata.name);
5265
await this.descriptionTextarea.fill(eventdata.name);
5366
await this.dateInput.fill(eventdata.date);
5467
await this.saveEventButton.click();
5568
await expect(this.successMessage).toBeVisible();
56-
(await this.getElementByTypeAndName('textbox','Search')).fill(eventdata.name);
57-
await this.page.keyboard.press('Enter');
58-
await this.page.
59-
69+
}
70+
async deleteEvent()
71+
{
72+
await this.deleteFirstEventButton.click();
73+
await this.agreeButton.click();
74+
await expect(this.successMessage).toBeVisible();
6075

6176
}
6277

63-
78+
79+
6480
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { test } from "../../fixtures/AdminFixtures";
2+
import { AdminPage } from "../../pages/AdminPage";
3+
import { campaignData, CampaignsPage } from "../../pages/settings/settings-pages/CampaignsPage";
4+
import { EventsPage } from "../../pages/settings/settings-pages/EventsPage";
5+
6+
test.describe('campaign management ',()=>{
7+
8+
9+
test('create evenet before campaign to assign event to campaign',async({adminPage})=>{
10+
const event=await new EventsPage(adminPage);
11+
await event.navigateToEvents();
12+
await event.createEvent(campaignData.event);
13+
14+
})
15+
16+
17+
test('campaing create',async({adminPage})=>{
18+
const campaign=new CampaignsPage(adminPage);
19+
20+
await campaign.navigateToCampaigns();
21+
22+
await campaign.createCampaign(campaignData);
23+
await campaign.searchByName(campaignData.name);
24+
campaignData.name="updated name";
25+
await campaign.editCampaign(campaignData);
26+
await campaign.searchByName(campaignData.name);
27+
await campaign.deleteCampaign();
28+
29+
30+
})
31+
})
Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1+
import { env } from "process";
12
import { test } from "../../fixtures/AdminFixtures";
23
import { eventdata, EventsPage } from "../../pages/settings/settings-pages/EventsPage";
34

45
test.describe('event management', () => {
56

6-
test('create event', async ({ adminPage }) => {
7-
const event = new EventsPage(adminPage);
8-
await event.gotoEventsPage()
9-
await event.openCreateEventModal()
10-
await event.createEvent(eventdata);
7+
8+
9+
test('create event', async ({ adminPage }) => {
10+
const event = await new EventsPage(adminPage);
11+
await event.navigateToEvents();
12+
await event.createEvent(eventdata);
13+
await event.searchByName(eventdata.name);
14+
await event.deleteEvent();
1115

12-
13-
})
16+
})
1417
})

0 commit comments

Comments
 (0)