Skip to content

Commit

Permalink
feat: customer bulk edit
Browse files Browse the repository at this point in the history
  • Loading branch information
vanpham-sw committed Dec 3, 2024
1 parent abf091f commit 5046b84
Show file tree
Hide file tree
Showing 8 changed files with 297 additions and 1 deletion.
7 changes: 7 additions & 0 deletions src/page-objects/AdministrationPages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { RuleCreate } from './administration/RuleCreate';
import { ManufacturerCreate } from './administration/ManufacturerCreate';
import { ManufacturerListing } from './administration/ManufacturerListing';
import { ManufacturerDetail } from './administration/ManufacturerDetail';
import { CustomerBulkEdit } from './administration/CustomerBulkEdit';

export interface AdministrationPageTypes {
AdminProductDetail: ProductDetail;
Expand Down Expand Up @@ -55,6 +56,7 @@ export interface AdministrationPageTypes {
AdminManufacturerCreate: ManufacturerCreate,
AdminManufacturerListing: ManufacturerListing,
AdminManufacturerDetail: ManufacturerDetail,
AdminCustomerBulkEdit: CustomerBulkEdit;
}

export const AdminPageObjects = {
Expand Down Expand Up @@ -84,6 +86,7 @@ export const AdminPageObjects = {
ManufacturerCreate,
ManufacturerDetail,
ManufacturerListing,
CustomerBulkEdit,
}

export const test = base.extend<FixtureTypes>({
Expand Down Expand Up @@ -191,4 +194,8 @@ export const test = base.extend<FixtureTypes>({
AdminManufacturerDetail: async ({ AdminPage }, use) => {
await use(new ManufacturerDetail(AdminPage));
},

AdminCustomerBulkEdit: async ({ AdminPage }, use) => {
await use(new CustomerBulkEdit(AdminPage));
},
});
91 changes: 91 additions & 0 deletions src/page-objects/administration/CustomerBulkEdit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { PageObject } from '../../types/PageObject';
import { Locator, Page } from '@playwright/test';


export class CustomerBulkEdit implements PageObject{

//General
public readonly applyChangesButton: Locator;
public readonly filtersResultPopoverItemList: Locator;

//Account
public readonly changeCustomerGroupCheckbox: Locator;
public readonly customerGroupInput: Locator;
public readonly changeAccountStatusCheckbox: Locator;
public readonly accountStatusInput: Locator;
public readonly changeLanguageCheckbox: Locator;
public readonly changeLanguageInput: Locator;
public readonly replyToCustomerGroupRequest: Locator;
public readonly replyToCustomerGroupRequestInput: Locator;

//Tags
public readonly changeTagsCheckbox: Locator;
public readonly changeTypeSelect: Locator;
public readonly enterTagsSelect: Locator;

//Custom fields
public readonly customFieldCheckbox: Locator;
public readonly customFieldInput: Locator;
public readonly customFieldArrowRightButton: Locator;

/**
* Confirmation modal
*/
public readonly confirmModal: Locator;
public readonly confirmModalApplyChangesButton: Locator;
public readonly confirmModalSuccessHeader: Locator;
public readonly confirmModalSuccessCloseButton: Locator;

constructor(readonly page: Page){
//General
this.applyChangesButton = page.getByRole('button', { name: 'Apply changes' });
this.filtersResultPopoverItemList = page.locator('.sw-select-result-list__content').getByRole('listitem');
//Account
this.changeCustomerGroupCheckbox = page.getByRole('checkbox', { name: 'Change: Customer group' });
this.customerGroupInput = page.locator('.sw-select').filter({ hasText: 'Select customer group...' }).locator('.sw-select__selection');
const accountStatus = page.locator('.sw-bulk-edit-change-field-active');
this.changeAccountStatusCheckbox = accountStatus.getByRole('checkbox', { name: 'Change: Account status' });
this.accountStatusInput = accountStatus.locator('.sw-field--switch__input');
this.changeLanguageCheckbox = page.getByRole('checkbox', { name: 'Change: Language' });
this.changeLanguageInput = page.locator('.sw-select').filter({ hasText: 'Select language...' }).locator('.sw-select__selection');
this.replyToCustomerGroupRequest = page.getByRole('checkbox', { name: 'Reply to: Customer group request' });
this.replyToCustomerGroupRequestInput = page.locator('.sw-select').filter({ hasText: 'Select customer group request reply...' }).locator('.sw-select__selection');
//Tags
const changeTag = page.locator('.sw-bulk-edit-change-field-tags');
this.changeTagsCheckbox = changeTag.getByRole('checkbox', { name: 'Change: Tags' });
this.changeTypeSelect = changeTag.locator('.sw-bulk-edit-change-type__selection');
this.enterTagsSelect = changeTag.locator('.sw-entity-multi-select');

//Custom fields
const customFields = page.locator('.sw-bulk-edit__custom-fields');
this.customFieldArrowRightButton = customFields.locator('.sw-tabs__arrow--right');
this.customFieldCheckbox = customFields.getByRole('checkbox');
this.customFieldInput = customFields.getByRole('textbox');

//Confirmation modal
this.confirmModal = page.locator('.sw-bulk-edit-save-modal');
this.confirmModalApplyChangesButton = this.confirmModal.getByRole('button', {name: 'Apply changes'});
this.confirmModalSuccessHeader = this.confirmModal.getByRole('heading', {name: 'Bulk edit - Success'});
const footer = this.confirmModal.locator('.sw-modal__footer');
this.confirmModalSuccessCloseButton = footer.getByRole('button', {name: 'Close'});
}

async getPageHeadline(customerCount: number): Promise<Locator> {
return this.page.getByRole('heading', { name:`Bulk edit: ${customerCount} customer` })
}

async getCustomFieldInputByName(customFieldName: string): Promise<Locator> {
return this.page.getByRole('textbox', { name: customFieldName });
}

async getCustomFieldLinkByName(customFieldSetName: string): Promise<Locator> {
return this.page.locator('a').filter({
hasText: `${customFieldSetName}`,
});
}

url(): string {
return '#/sw/bulk/edit/customer';
}

}
25 changes: 25 additions & 0 deletions src/page-objects/administration/CustomerDetail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export class CustomerDetail implements PageObject {
public readonly customerGroupRequestMessage: Locator;
public readonly customerGroupAcceptButton: Locator;
public readonly customerGroupDeclineButton: Locator;
public readonly tagList: Locator;
public readonly tagItems: Locator;

constructor(public readonly page: Page) {
this.editButton = page.getByRole('button', { name: 'Edit' });
Expand All @@ -22,6 +24,8 @@ export class CustomerDetail implements PageObject {
this.customerGroupRequestMessage = page.locator('.sw-alert__message');
this.customerGroupAcceptButton = page.getByRole('button', { name: 'Accept' });
this.customerGroupDeclineButton = page.getByRole('button', { name: 'Decline' });
this.tagList = page.locator('.sw-customer-card__tag-select').locator('.sw-select-selection-list');
this.tagItems = this.tagList.locator('.sw-select-selection-list__item');
}

async getCustomFieldSetCardContentByName(customFieldSetName: string): Promise<Record<string, Locator>> {
Expand All @@ -41,6 +45,27 @@ export class CustomerDetail implements PageObject {
return this.customerGroupRequestMessage.getByText(`Access to customer group "${customerGroup}" requested.`);
}

async getCustomerGroup() : Promise<Locator> {
const dlElement = this.page.locator('dl').filter({
has: this.page.locator('dt', { hasText: 'Customer group' }),
});
return dlElement.locator('dd');
}

async getAccountStatus() : Promise<Locator> {
const dlElement = this.page.locator('dl').filter({
has: this.page.locator('dt', { hasText: 'Account status' }),
});
return dlElement.locator('dd');
}

async getLanguage() : Promise<Locator> {
const dlElement = this.page.locator('dl').filter({
has: this.page.locator('dt', { hasText: 'Language' }),
});
return dlElement.locator('dd');
}

url(customerId: string) {
return `#/sw/customer/detail/${customerId}/base`;
}
Expand Down
46 changes: 46 additions & 0 deletions src/page-objects/administration/CustomerListing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,27 @@ import type { PageObject } from '../../types/PageObject';
export class CustomerListing implements PageObject {
public readonly headline: Locator;
public readonly addCustomerButton: Locator;
public readonly bulkEditButton: Locator;
public readonly deleteButton: Locator

//Customer Bulk Edit Modal
public readonly bulkEditModal: Locator;
public readonly startBulkEditButton: Locator;
public readonly cancelButton: Locator;
public readonly modalHeaderCheckbox: Locator;

constructor(public readonly page: Page) {
this.headline = page.getByRole('heading', { name: 'Customers' });
this.addCustomerButton = page.locator('.sw-customer-list__button-create');
this.bulkEditButton = page.getByRole('button', { name: 'Bulk edit' });
this.deleteButton = page.getByRole('button', { name: 'Delete' });

//Customer Bulk Edit Modal
this.bulkEditModal = page.locator('.sw-customer-bulk-edit-modal').getByRole('dialog');
this.startBulkEditButton = this.bulkEditModal.getByRole('button', { name: 'Start bulk edit' });
this.cancelButton = this.bulkEditModal.getByRole('button', { name: 'Cancel' });
const tableHeader = this.bulkEditModal.locator('.sw-data-grid__header');
this.modalHeaderCheckbox = tableHeader.getByRole('checkbox');
}

async getCustomerByEmail(customerEmail: string): Promise<Record<string, Locator>> {
Expand All @@ -20,8 +37,37 @@ export class CustomerListing implements PageObject {
const customerNumber = customer.locator('.sw-data-grid__cell--customerNumber')
const customerGroup = customer.locator('.sw-data-grid__cell--group');
const customerEmailAddress = customer.locator('.sw-data-grid__cell--email');
const customerCheckbox = customer.getByRole('checkbox');

return {
customerName: customerName,
customerStreet: customerStreet,
customerPostalCode: customerPostalCode,
customerCity: customerCity,
customerNumber: customerNumber,
customerGroup: customerGroup,
customerEmailAddress: customerEmailAddress,
customerCheckbox: customerCheckbox,
}
}

async getCustomerBulkEditModalTitle(customerCount: number): Promise<Locator> {
return this.bulkEditModal.getByRole('heading', { name: `Bulk edit - ${customerCount} items selected` });
}

async getBulkEditModalLineItemByCustomerEmail(customerEmail: string): Promise<Record<string, Locator>> {
const lineItem = this.bulkEditModal.locator('.sw-data-grid__row').filter({ hasText: customerEmail });
const customerCheckbox = lineItem.getByRole('checkbox');
const customerName = lineItem.locator('.sw-data-grid__cell--firstName').getByRole('link');
const customerStreet = lineItem.locator('.sw-data-grid__cell--defaultBillingAddress-street');
const customerPostalCode = lineItem.locator('.sw-data-grid__cell--defaultBillingAddress-zipcode');
const customerCity = lineItem.locator('.sw-data-grid__cell--defaultBillingAddress-city');
const customerNumber = lineItem.locator('.sw-data-grid__cell--customerNumber')
const customerGroup = lineItem.locator('.sw-data-grid__cell--group');
const customerEmailAddress = lineItem.locator('.sw-data-grid__cell--email');

return {
customerCheckbox: customerCheckbox,
customerName: customerName,
customerStreet: customerStreet,
customerPostalCode: customerPostalCode,
Expand Down
47 changes: 46 additions & 1 deletion src/services/TestDataService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createRandomImage } from './ImageHelper';
import { getPromotionWithDiscount } from './ShopwareDataHelpers';
import { getLanguageData, getPromotionWithDiscount } from './ShopwareDataHelpers';
import type { AdminApiContext } from './AdminApiContext';
import type { IdProvider } from './IdProvider';
import type {
Expand Down Expand Up @@ -28,6 +28,7 @@ import type {
Country,
CustomerGroup,
SystemConfig,
Language,
} from '../types/ShopwareTypes';
import { expect } from '@playwright/test';

Expand Down Expand Up @@ -1111,6 +1112,22 @@ export class TestDataService {
return salesChannel;
}

async addSalesChannelLanguage(salesChannelId: string, languageCode: string) {
const language = await getLanguageData(languageCode, this.AdminApiClient);

const syncSalesChannelResponse = await this.AdminApiClient.patch(`sales-channel/${salesChannelId}`, {
data: {
id:salesChannelId,
languages:[
{
id:language.id,
},
],
},
});
expect(syncSalesChannelResponse.ok()).toBeTruthy();
}

/**
* Assigns a media resource to a payment method as a logo.
*
Expand Down Expand Up @@ -1392,6 +1409,34 @@ export class TestDataService {
return result;
}

/**
* Retrieves a customer group by its id.
*
* @param customerGroupId - The id of the property group.
*/
async getCustomerGroupById(customerGroupId: string): Promise<CustomerGroup> {
const response = await this.AdminApiClient.get(`customer-group/${customerGroupId}`);
expect(response.ok()).toBeTruthy();

const { data: customerGroup } = (await response.json()) as { data: CustomerGroup };

return customerGroup;
}

/**
* Retrieves a language by its id.
*
* @param languageId - The id of the property group.
*/
async getLanguageById(languageId: string): Promise<Language> {
const response = await this.AdminApiClient.get(`language/${languageId}`);
expect(response.ok()).toBeTruthy();

const { data: language } = (await response.json()) as { data: Language };

return language;
}

/**
* Adds an entity reference to the registry of created records.
* All entities added to the registry will be deleted by the cleanup call.
Expand Down
2 changes: 2 additions & 0 deletions src/tasks/shop-admin-tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { mergeTests } from '@playwright/test';
import { SaveProduct } from './shop-admin/Product/SaveProduct';
import { ExpectNotification } from './shop-admin/ExpectNotification';
import { CreateLinkTypeCategory } from './shop-admin/Category/CreateLinkTypeCategory';
import { BulkEditCustomers } from './shop-admin/Customers/BulkEditCustomers';

export const test = mergeTests(
SaveProduct,
ExpectNotification,
CreateLinkTypeCategory,
BulkEditCustomers
);
Loading

0 comments on commit 5046b84

Please sign in to comment.