diff --git a/src/index.ts b/src/index.ts index 102b43d9..928fdd86 100644 --- a/src/index.ts +++ b/src/index.ts @@ -213,6 +213,7 @@ export {default as boMaintenancePage} from '@pages/BO/shopParameters/general/mai export {default as boModuleManagerPage} from '@pages/BO/modules/moduleManager'; export {default as boModuleManagerAlertsPage} from '@pages/BO/modules/moduleManager/alerts'; export {default as boModuleManagerUninstalledModulesPage} from '@pages/BO/modules/moduleManager/uninstalledModules'; +export {default as boMyProfilePage} from '@pages/BO/advancedParameters/team/myProfile'; export {default as boNewExperimentalFeaturesPage} from '@pages/BO/advancedParameters/newExperimentalFeatures'; export {default as boOrdersPage} from '@pages/BO/orders'; export {default as boOrdersViewBasePage} from '@pages/BO/orders/view/viewOrderBasePage'; diff --git a/src/interfaces/BO/advancedParameters/team/base.ts b/src/interfaces/BO/advancedParameters/team/base.ts new file mode 100644 index 00000000..6509a7b2 --- /dev/null +++ b/src/interfaces/BO/advancedParameters/team/base.ts @@ -0,0 +1,6 @@ +import {BOBasePagePageInterface} from '@interfaces/BO'; + +export interface BOTeamBasePageInterface extends BOBasePagePageInterface { + readonly pageTitleEdit: (firstName: string, lastName: string) => string; + readonly pageTitleEditFr: (firstName: string, lastName: string) => string; +} diff --git a/src/interfaces/BO/advancedParameters/team/myProfile.ts b/src/interfaces/BO/advancedParameters/team/myProfile.ts new file mode 100644 index 00000000..7823320b --- /dev/null +++ b/src/interfaces/BO/advancedParameters/team/myProfile.ts @@ -0,0 +1,15 @@ +import type FakerEmployee from '@data/faker/employee'; +import {type BOTeamBasePageInterface} from '@interfaces/BO/advancedParameters/team/base'; +import type {Page} from '@playwright/test'; + +export interface BOMyProfilePageInterface extends BOTeamBasePageInterface { + readonly errorInvalidFirstNameMessage: string; + readonly errorInvalidFormatImageMessage: string; + readonly errorInvalidLastNameMessage: string; + readonly successfulUpdateMessageFR: string; + + getAlertError(page: Page): Promise; + getAlertSuccess(page: Page): Promise; + isGravatarEnabled(page: Page): Promise; + updateEditEmployee(page: Page, currentPassword: string, newEmployeeData: FakerEmployee): Promise; +} diff --git a/src/interfaces/BO/index.ts b/src/interfaces/BO/index.ts index 030c53d2..5aa81ecd 100644 --- a/src/interfaces/BO/index.ts +++ b/src/interfaces/BO/index.ts @@ -88,6 +88,7 @@ export interface BOBasePagePageInterface extends CommonPageInterface { getAlertSuccessBlockContent(page: Frame | Page): Promise; getAlertSuccessBlockParagraphContent(page: Frame | Page): Promise; getAllNotificationsNumber(page: Page): Promise; + getCurrentEmployeeAvatar(page: Page): Promise; getHelpDocumentURL(page: Page): Promise; getNotificationsNumberInTab(page: Page, tabName: string): Promise; getPageSubTitle(page: Page): Promise; diff --git a/src/pages/BO/advancedParameters/team/base.ts b/src/pages/BO/advancedParameters/team/base.ts new file mode 100644 index 00000000..51e4e708 --- /dev/null +++ b/src/pages/BO/advancedParameters/team/base.ts @@ -0,0 +1,89 @@ +import {type BOTeamBasePageInterface} from '@interfaces/BO/advancedParameters/team/base'; +import BOBasePage from '@pages/BO/BOBasePage'; +import {type Page} from '@playwright/test'; + +/** + * Employee base page, contains functions that can be used on the page + * @class + * @extends BOBasePage + */ +export default class EmployeeBasePage extends BOBasePage implements BOTeamBasePageInterface { + public readonly pageTitleEdit: (firstName: string, lastName: string) => string; + + public readonly pageTitleEditFr: (firstName: string, lastName: string) => string; + + protected readonly firstNameInput: string; + + protected readonly lastNameInput: string; + + protected readonly emailInput: string; + + private readonly defaultPageSpan: string; + + private readonly searchDefaultPageInput: string; + + protected readonly languageSelect: string; + + protected readonly statusToggleInput: (toggle: number) => string; + + protected readonly permissionProfileSelect: string; + + protected readonly saveButton: string; + + private readonly cancelButton: string; + + /** + * @constructs + * Setting up texts and selectors to use on Employee page + */ + constructor() { + super(); + + this.pageTitleEdit = (firstName: string, lastName: string) => `Editing ${firstName} ${lastName}'s profile` + + ` • ${global.INSTALL.SHOP_NAME}`; + this.pageTitleEditFr = (firstName: string, lastName: string) => `Modification du profil de ${firstName} ${lastName}` + + ` • ${global.INSTALL.SHOP_NAME}`; + + // Selectors + this.firstNameInput = '#employee_firstname'; + this.lastNameInput = '#employee_lastname'; + this.emailInput = '#employee_email'; + this.defaultPageSpan = '.select2-selection[aria-labelledby=\'select2-employee_default_page-container\']'; + this.searchDefaultPageInput = '.select2-search__field'; + this.languageSelect = '#employee_language'; + this.statusToggleInput = (toggle: number) => `#employee_active_${toggle}`; + this.permissionProfileSelect = '#employee_profile'; + this.saveButton = '#save-button'; + this.cancelButton = '#cancel-link'; + } + + /* + Methods + */ + + /** + * Select default Page + * @param page {Page} Browser tab + * @param defaultPage {string} Page name to set on input + * @returns {Promise} + */ + async selectDefaultPage(page: Page, defaultPage: string): Promise { + await Promise.all([ + page.locator(this.defaultPageSpan).click(), + this.waitForVisibleSelector(page, `${this.defaultPageSpan}[aria-expanded='true']`), + ]); + await this.setValue(page, this.searchDefaultPageInput, defaultPage); + await page.keyboard.press('Enter'); + } + + /** + * Cancel the creation or the update and return to the listing page + * @param page {Page} Browser tab + * @returns {Promise} + */ + async cancel(page: Page): Promise { + await this.clickAndWaitForURL(page, this.cancelButton); + } +} + +module.exports = EmployeeBasePage; diff --git a/src/pages/BO/advancedParameters/team/myProfile.ts b/src/pages/BO/advancedParameters/team/myProfile.ts new file mode 100644 index 00000000..622c45f1 --- /dev/null +++ b/src/pages/BO/advancedParameters/team/myProfile.ts @@ -0,0 +1,9 @@ +import type {BOMyProfilePageInterface} from '@interfaces/BO/advancedParameters/team/myProfile'; + +/* eslint-disable global-require, @typescript-eslint/no-var-requires */ +function requirePage(): BOMyProfilePageInterface { + return require('@versions/develop/pages/BO/advancedParameters/team/myProfile'); +} +/* eslint-enable global-require, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/versions/develop/pages/BO/advancedParameters/team/myProfile.ts b/src/versions/develop/pages/BO/advancedParameters/team/myProfile.ts new file mode 100644 index 00000000..0cfc9662 --- /dev/null +++ b/src/versions/develop/pages/BO/advancedParameters/team/myProfile.ts @@ -0,0 +1,133 @@ +import type FakerEmployee from '@data/faker/employee'; +import {type BOMyProfilePageInterface} from '@interfaces/BO/advancedParameters/team/myProfile'; +import EmployeeBasePage from '@pages/BO/advancedParameters/team/base'; +import {type Page} from '@playwright/test'; + +/** + * Add employee page, contains functions that can be used on the page + * @class + * @extends EmployeeBasePage + */ +class BOMyProfilePage extends EmployeeBasePage implements BOMyProfilePageInterface { + public readonly successfulUpdateMessageFR: string; + + public readonly errorInvalidFirstNameMessage: string; + + public readonly errorInvalidLastNameMessage: string; + + public readonly errorInvalidFormatImageMessage: string; + + private readonly passwordButton: string; + + private readonly currentPasswordInput: string; + + private readonly newPasswordInput: string; + + private readonly confirmPasswordInput: string; + + private readonly avatarFileInput: string; + + private readonly enableGravatarInput: (toggle: number) => string; + + /** + * @constructs + * Setting up texts and selectors to use on add employee page + */ + constructor() { + super(); + + this.successfulUpdateMessageFR = 'Mise à jour réussie'; + this.errorInvalidFirstNameMessage = 'The "First name" field is invalid.'; + this.errorInvalidLastNameMessage = 'The "Last name" field is invalid.'; + this.errorInvalidFormatImageMessage = 'Image format not recognized, allowed formats are: image/gif, image/jpg, ' + + 'image/jpeg, image/pjpeg, image/png, image/x-png, image/webp, image/svg+xml, image/svg'; + + // Selectors + this.passwordButton = '#employee_change_password_change_password_button'; + this.currentPasswordInput = '#employee_change_password_old_password'; + this.newPasswordInput = '#employee_change_password_new_password_first'; + this.confirmPasswordInput = '#employee_change_password_new_password_second'; + this.avatarFileInput = '#employee_avatarUrl'; + this.enableGravatarInput = (toggle: number) => `#employee_has_enabled_gravatar_${toggle}`; + } + + /* + Methods + */ + + /** + * Fill form for update My Profile page + * @param page {Page} Browser tab + * @param currentPassword {string} Data to set on add/edit employee form + * @param newEmployeeData {FakerEmployee} Data to set on add/edit employee form + * @returns {Promise} + */ + async updateEditEmployee(page: Page, currentPassword: string, newEmployeeData: FakerEmployee): Promise { + await this.setValue(page, this.firstNameInput, newEmployeeData.firstName); + await this.setValue(page, this.lastNameInput, newEmployeeData.lastName); + if (newEmployeeData.avatarFile) { + await this.uploadOnFileChooser(page, this.avatarFileInput, [newEmployeeData.avatarFile]); + } + await this.setChecked(page, this.enableGravatarInput(newEmployeeData.enableGravatar ? 1 : 0)); + await this.setValue(page, this.emailInput, newEmployeeData.email); + await page.locator(this.passwordButton).click(); + await this.setValue(page, this.currentPasswordInput, currentPassword); + await this.setValue(page, this.newPasswordInput, newEmployeeData.password); + await this.setValue(page, this.confirmPasswordInput, newEmployeeData.password); + await this.selectByVisibleText(page, this.languageSelect, newEmployeeData.language); + await this.selectDefaultPage(page, newEmployeeData.defaultPage); + await this.clickAndWaitForLoadState(page, this.saveButton); + } + + /** + * Get the value of an input + * @override + * @param page {Page} Browser tab + * @param input {string} ID of the input + * @returns {Promise} + */ + async getInputValue(page: Page, input: string): Promise { + let inputSelector: string; + + switch (input) { + case 'firstname': + inputSelector = this.firstNameInput; + break; + case 'lastname': + inputSelector = this.lastNameInput; + break; + default: + throw new Error(`Field ${input} was not found`); + } + + return super.getInputValue(page, inputSelector); + } + + /** + * Get login error + * @param page {Page} Browser tab + * @return {Promise} + */ + async getAlertSuccess(page: Page): Promise { + return this.getAlertSuccessBlockParagraphContent(page); + } + + /** + * Get login error + * @param page {Page} Browser tab + * @return {Promise} + */ + async getAlertError(page: Page): Promise { + return this.getAlertDangerBlockParagraphContent(page); + } + + /** + * @param page {Page} Browser tab + * @return {Promise} + */ + async isGravatarEnabled(page: Page): Promise { + return this.isChecked(page, this.enableGravatarInput(1)); + } +} + +module.exports = new BOMyProfilePage();