diff --git a/src/data/demo/products.ts b/src/data/demo/products.ts index 3b7f079a9..c3f3516e4 100644 --- a/src/data/demo/products.ts +++ b/src/data/demo/products.ts @@ -9,9 +9,9 @@ export default { category: 'Men', summary: 'Regular fit, round neckline, short sleeves. Made of extra long staple pima cotton.', description: 'Symbol of lightness and delicacy, the hummingbird evokes curiosity and joy. Studio Design\' ' - + 'PolyFaune collection features classic products with colorful patterns, inspired by the traditional japanese ' - + 'origamis. To wear with a chino or jeans. The sublimation textile printing process provides an exceptional ' - + 'color rendering and a color, guaranteed overtime.', + + 'PolyFaune collection features classic products with colorful patterns, inspired by the traditional japanese ' + + 'origamis. To wear with a chino or jeans. The sublimation textile printing process provides an exceptional ' + + 'color rendering and a color, guaranteed overtime.', retailPrice: 28.68, tax: 20, price: 23.90, diff --git a/src/data/faker/product.ts b/src/data/faker/product.ts index 6aeb1b7fd..0462258e2 100644 --- a/src/data/faker/product.ts +++ b/src/data/faker/product.ts @@ -134,12 +134,12 @@ export default class FakerProduct { public deliveryTime: string; /** - * Constructor for class FakerProduct - * @param productToCreate {Object} Could be used to force the value of some members - * @todo Replace taxRule & tax by FakerTax object - * @todo Rename price to priceTaxIncluded - * @todo Check if retailPrice & finalPrice can be removed - */ + * Constructor for class FakerProduct + * @param productToCreate {Object} Could be used to force the value of some members + * @todo Replace taxRule & tax by FakerTax object + * @todo Rename price to priceTaxIncluded + * @todo Check if retailPrice & finalPrice can be removed + */ constructor(productToCreate: ProductCreator = {}) { /** @type {number} ID of the product */ this.id = productToCreate.id || 0; diff --git a/src/data/faker/productReview.ts b/src/data/faker/productReview.ts index aa77e0597..71a065d46 100644 --- a/src/data/faker/productReview.ts +++ b/src/data/faker/productReview.ts @@ -14,17 +14,17 @@ export default class FakerProductReview { public reviewRating: number; /** - * Constructor for class ProductReview - * @param productReviewToCreate {ProductReviewCreator} Could be used to add a review on a product - */ + * Constructor for class ProductReview + * @param productReviewToCreate {ProductReviewCreator} Could be used to add a review on a product + */ constructor(productReviewToCreate: ProductReviewCreator = {}) { /** @type {string} Title of the review */ this.reviewTitle = productReviewToCreate.reviewTitle - || faker.lorem.sentence(faker.number.int({min: 3, max: 7})); + || faker.lorem.sentence(faker.number.int({min: 3, max: 7})); /** @type {string} Content of the review */ this.reviewContent = productReviewToCreate.reviewContent - || faker.lorem.sentences(faker.number.int({min: 3, max: 10})); + || faker.lorem.sentences(faker.number.int({min: 3, max: 10})); /** @type {number} Rating of the review */ this.reviewRating = productReviewToCreate.reviewRating || faker.number.int({min: 1, max: 5}); diff --git a/src/data/types/product.ts b/src/data/types/product.d.ts similarity index 99% rename from src/data/types/product.ts rename to src/data/types/product.d.ts index e18b79673..5b9cff4ae 100644 --- a/src/data/types/product.ts +++ b/src/data/types/product.d.ts @@ -279,4 +279,5 @@ export type { ProductFeatures, ProductFiles, ProductCustomizations, + ProductOrderConfirmation, }; diff --git a/src/index.ts b/src/index.ts index b9fdafedd..911833943 100644 --- a/src/index.ts +++ b/src/index.ts @@ -203,6 +203,7 @@ export {default as boLocalizationPage} from '@pages/BO/international/localizatio export {default as boLoginPage} from '@pages/BO/login'; export {default as boModuleManagerPage} from '@pages/BO/modules/moduleManager'; export {default as boModuleManagerAlertsPage} from '@pages/BO/modules/moduleManager/alerts'; +export {default as boModuleManagerSelectionPage} from '@pages/BO/modules/moduleManager/selection'; export {default as boModuleManagerUninstalledModulesPage} from '@pages/BO/modules/moduleManager/uninstalledModules'; export {default as boNewExperimentalFeaturesPage} from '@pages/BO/advancedParameters/newExperimentalFeatures'; export {default as boOrdersPage} from '@pages/BO/orders'; @@ -222,6 +223,7 @@ export {default as boProductsCreateTabSEOPage} from '@pages/BO/catalog/products/ export {default as boProductsCreateTabShippingPage} from '@pages/BO/catalog/products/create/tabShipping'; export {default as boProductsCreateTabStocksPage} from '@pages/BO/catalog/products/create/tabStocks'; export {default as boProductsCreateTabVirtualProductPage} from '@pages/BO/catalog/products/create/tabVirtualProduct'; +export {default as boRouterPage} from '@pages/BO/BORouterPage'; export {default as boSearchPage} from '@pages/BO/shopParameters/search'; export {default as boSearchAliasCreatePage} from '@pages/BO/shopParameters/search/alias/create'; export {default as boThemeAdvancedConfigurationPage} from '@pages/BO/design/themeAndLogo/advancedConfiguration'; diff --git a/src/interfaces/BO/modules/moduleManager/selection.ts b/src/interfaces/BO/modules/moduleManager/selection.ts new file mode 100644 index 000000000..6784ac386 --- /dev/null +++ b/src/interfaces/BO/modules/moduleManager/selection.ts @@ -0,0 +1,11 @@ +import {BOBasePagePageInterface} from '@interfaces/BO'; +import type {Page} from '@playwright/test'; + +export interface ModuleManagerSelectionPageInterface extends BOBasePagePageInterface { + readonly installMessageSuccessful: (moduleTag: string) => string; + readonly pageTitle: string; + + goToTabSelection(page: Page): Promise; + goToTabInstalledModules(page: Page): Promise; + installModule(page: Page, moduleTag: string): Promise; +} diff --git a/src/interfaces/BO/router.ts b/src/interfaces/BO/router.ts new file mode 100644 index 000000000..b88c91525 --- /dev/null +++ b/src/interfaces/BO/router.ts @@ -0,0 +1,6 @@ +import type {BOBasePagePageInterface} from '@interfaces/BO/index'; +import type {Frame, Page} from '@playwright/test'; + +export interface BORouterPageInterface extends BOBasePagePageInterface { + goToModuleManagerPage(page: Page): Promise; +} diff --git a/src/pages/BO/BOBasePage.ts b/src/pages/BO/BOBasePage.ts index b2185caa8..dd9b07558 100644 --- a/src/pages/BO/BOBasePage.ts +++ b/src/pages/BO/BOBasePage.ts @@ -731,22 +731,31 @@ export default class BOBasePage extends CommonPage implements BOBasePagePageInte * @returns {Promise} */ async goToSubMenu(page: Page, parentSelector: string, linkSelector: string): Promise { - await this.clickSubMenu(page, parentSelector); - await this.scrollTo(page, linkSelector); - await this.clickAndWaitForURL(page, linkSelector); + const psVersion = testContext.getPSVersion(); - const shopVersion = testContext.getPSVersion(); let linkActiveClass: string = '-active'; - // >= 1.7.8.0 - if (semver.gte(shopVersion, '7.8.0')) { - linkActiveClass = 'link-active'; - } + // >= 1.7.4.0 + if (semver.gte(psVersion, '7.4.0')) { + await this.clickSubMenu(page, parentSelector); + await this.scrollTo(page, linkSelector); + await this.clickAndWaitForURL(page, linkSelector); + + // >= 1.7.8.0 + if (semver.gte(psVersion, '7.8.0')) { + linkActiveClass = 'link-active'; + } - if (await this.isSidebarCollapsed(page)) { - await this.waitForHiddenSelector(page, `${linkSelector}.${linkActiveClass}`); + if (await this.isSidebarCollapsed(page)) { + await this.waitForHiddenSelector(page, `${linkSelector}.${linkActiveClass}`); + } else { + await this.waitForVisibleSelector(page, `${linkSelector}.${linkActiveClass}`); + } } else { - await this.waitForVisibleSelector(page, `${linkSelector}.${linkActiveClass}`); + await page.locator(parentSelector).hover(); + await this.waitForVisibleSelector(page, linkSelector); + await this.clickAndWaitForURL(page, linkSelector); + await this.waitForVisibleSelector(page, `${parentSelector}.${linkActiveClass}`); } } @@ -1072,7 +1081,16 @@ export default class BOBasePage extends CommonPage implements BOBasePagePageInte * @return {Promise} */ async getGrowlMessageContent(page: Page, timeout: number = 10000): Promise { - return page.textContent(this.growlMessageBlock, {timeout}); + const psVersion = testContext.getPSVersion(); + let {growlMessageBlock} = this; + + if (semver.lt(psVersion, '8.0.0') && semver.gt(psVersion, '7.4.99')) { + growlMessageBlock = `${this.growlDiv} .growl-message`; + } + if (semver.lt(psVersion, '7.5.0')) { + growlMessageBlock = `${this.growlDefaultDiv} .growl-message`; + } + return page.textContent(growlMessageBlock, {timeout}); } /** diff --git a/src/pages/BO/BORouterPage.ts b/src/pages/BO/BORouterPage.ts new file mode 100644 index 000000000..9d3d76ad6 --- /dev/null +++ b/src/pages/BO/BORouterPage.ts @@ -0,0 +1,35 @@ +import {BORouterPageInterface} from '@interfaces/BO/router'; +import BOBasePage from '@pages/BO/BOBasePage'; +import boDashboardPage from '@pages/BO/dashboard/index'; +import boModuleManagerPage from '@pages/BO/modules/moduleManager/index'; +import boModuleManagerSelectionPage from '@pages/BO/modules/moduleManager/selection'; +import testContext from '@utils/testContext'; +import type {Page} from 'playwright-core'; +import semver from 'semver'; + +class BORouterPage extends BOBasePage implements BORouterPageInterface { + async goToModuleManagerPage(page: Page): Promise { + const psVersion = testContext.getPSVersion(); + const pageTitle = await this.getPageTitle(page); + const boModuleManagerLinkPageTitle = semver.lt(psVersion, '7.4.0') + ? boModuleManagerSelectionPage.pageTitle + : boModuleManagerPage.pageTitle; + + // Check if we are not already on the page + if (!pageTitle.includes(boModuleManagerLinkPageTitle)) { + await boDashboardPage.goToSubMenu( + page, + boDashboardPage.modulesParentLink, + boDashboardPage.moduleManagerLink, + ); + await boDashboardPage.closeSfToolBar(page); + } + + if (semver.lt(psVersion, '7.4.0')) { + console.log('goToTabInstalledModules'); + await boModuleManagerSelectionPage.goToTabInstalledModules(page); + } + } +} + +export default new BORouterPage(); diff --git a/src/pages/BO/login/index.ts b/src/pages/BO/login/index.ts index d1a59619a..c16105f15 100644 --- a/src/pages/BO/login/index.ts +++ b/src/pages/BO/login/index.ts @@ -6,8 +6,11 @@ const psVersion = testContext.getPSVersion(); /* eslint-disable global-require, @typescript-eslint/no-var-requires */ function requirePage(): LoginPageInterface { + if (semver.lt(psVersion, '7.3.0')) { + return require('@versions/1.7.2/pages/BO/login'); + } if (semver.lt(psVersion, '8.0.0')) { - return require('@versions/1.7.8/pages/BO/login'); + return require('@versions/1.7.8/pages/BO/login').loginPage; } if (semver.lt(psVersion, '9.0.0')) { return require('@versions/8.1/pages/BO/login').loginPage; diff --git a/src/pages/BO/modules/moduleManager/index.ts b/src/pages/BO/modules/moduleManager/index.ts index 5a91e3bee..3d9a4b928 100644 --- a/src/pages/BO/modules/moduleManager/index.ts +++ b/src/pages/BO/modules/moduleManager/index.ts @@ -2,6 +2,9 @@ import type {ModuleManagerPageInterface} from '@interfaces/BO/modules/moduleMana /* eslint-disable global-require, @typescript-eslint/no-var-requires */ function requirePage(): ModuleManagerPageInterface { + if (semver.lt(psVersion, '7.5.0')) { + return require('@versions/1.7.4/pages/BO/modules/moduleManager'); + } return require('@versions/develop/pages/BO/modules/moduleManager').moduleManagerPage; } /* eslint-enable global-require, @typescript-eslint/no-var-requires */ diff --git a/src/pages/BO/modules/moduleManager/selection.ts b/src/pages/BO/modules/moduleManager/selection.ts new file mode 100644 index 000000000..bb7467341 --- /dev/null +++ b/src/pages/BO/modules/moduleManager/selection.ts @@ -0,0 +1,19 @@ +import type {ModuleManagerSelectionPageInterface} from '@interfaces/BO/modules/moduleManager/selection'; +import testContext from '@utils/testContext'; +import semver from 'semver'; + +const psVersion = testContext.getPSVersion(); + +/* eslint-disable global-require, @typescript-eslint/no-var-requires */ +function requirePage(): ModuleManagerSelectionPageInterface { + if (semver.gte(psVersion, '7.5.0')) { + return require('@versions/mock/pages/BO/modules/moduleManager/selection'); + } + if (semver.gte(psVersion, '7.4.0')) { + return require('@versions/1.7.4/pages/BO/modules/moduleManager/selection').selectionPage; + } + return require('@versions/1.7.3/pages/BO/modules/moduleManager/selection'); +} +/* eslint-enable global-require, @typescript-eslint/no-var-requires */ + +export default requirePage(); diff --git a/src/pages/FO/FOBasePage.ts b/src/pages/FO/FOBasePage.ts index c90e1804e..78333749d 100644 --- a/src/pages/FO/FOBasePage.ts +++ b/src/pages/FO/FOBasePage.ts @@ -1,8 +1,9 @@ // Import pages import {FOBasePagePageInterface} from '@interfaces/FO'; import CommonPage from '@pages/commonPage'; - -import type {Page} from 'playwright'; +import utilsTest from '@utils/test'; +import type {Locator, Page} from 'playwright'; +import semver from 'semver'; /** * FO parent page, contains functions that can be used on all FO page @@ -44,7 +45,9 @@ export default class FOBasePage extends CommonPage implements FOBasePagePageInte private readonly languageSelectorList: string; - private readonly languageSelectorMenuItemLink: (language: string) => string; + private readonly languageSelectorMenuItemLink: string; + + private readonly languageSelectorMenuItemLinkLang: (language: string) => string; private readonly currencySelectorDiv: string; @@ -174,8 +177,9 @@ export default class FOBasePage extends CommonPage implements FOBasePagePageInte this.defaultLanguageSpan = `${this.languageSelectorDiv} button span`; this.languageSelectorExpandIcon = `${this.languageSelectorDiv} i.expand-more`; this.languageSelectorList = `${this.languageSelectorDiv} .js-dropdown.open`; - this.languageSelectorMenuItemLink = (language) => `${this.languageSelectorDiv} ul li ` - + `a[data-iso-code='${language}']`; + this.languageSelectorMenuItemLink = `${this.languageSelectorDiv} ul li a`; + this.languageSelectorMenuItemLinkLang = (language) => `${this.languageSelectorMenuItemLink + }[data-iso-code='${language}']`; this.currencySelectorDiv = '#_desktop_currency_selector'; this.defaultCurrencySpan = `${this.currencySelectorDiv} button span`; this.currencySelectorExpandIcon = `${this.currencySelectorDiv} i.expand-more`; @@ -409,7 +413,7 @@ export default class FOBasePage extends CommonPage implements FOBasePagePageInte page.locator(this.languageSelectorExpandIcon).click(), this.waitForVisibleSelector(page, this.languageSelectorList), ]); - await this.clickAndWaitForLoadState(page, this.languageSelectorMenuItemLink(lang)); + await this.clickAndWaitForLoadState(page, this.getLanguageSelector(page, lang)); } /** @@ -434,7 +438,7 @@ export default class FOBasePage extends CommonPage implements FOBasePagePageInte */ async languageExists(page: Page, lang: string = 'en'): Promise { await page.locator(this.languageSelectorExpandIcon).click(); - return this.elementVisible(page, this.languageSelectorMenuItemLink(lang), 1000); + return this.elementVisible(page, this.getLanguageSelector(page, lang), 1000); } /** @@ -818,6 +822,19 @@ export default class FOBasePage extends CommonPage implements FOBasePagePageInte async getRestrictedText(page: Page): Promise { return page.locator(this.restrictedText).textContent(); } + + private getLanguageSelector(page: Page, lang: string): string|Locator { + const psVersion = utilsTest.getPSVersion(); + + // >= 1.7.5.0 + if (semver.gte(psVersion, '7.5.0')) { + return this.languageSelectorMenuItemLinkLang(lang); + } + + return page.locator(this.languageSelectorMenuItemLink).filter({ + hasText: lang === 'en' ? 'English' : 'Français', + }); + } } module.exports = FOBasePage; diff --git a/src/pages/FO/classic/product/index.ts b/src/pages/FO/classic/product/index.ts index 47f5e0511..9fb40370c 100644 --- a/src/pages/FO/classic/product/index.ts +++ b/src/pages/FO/classic/product/index.ts @@ -1,7 +1,14 @@ import type {FoProductPageInterface} from '@interfaces/FO/product'; +import testContext from '@utils/test'; +import semver from 'semver'; + +const psVersion = testContext.getPSVersion(); /* eslint-disable global-require, @typescript-eslint/no-var-requires */ function requirePage(): FoProductPageInterface { + if (semver.lt(psVersion, '9.0.0')) { + return require('@versions/8.1.0/pages/FO/classic/product'); + } return require('@versions/develop/pages/FO/classic/product').productPage; } /* eslint-enable global-require, @typescript-eslint/no-var-requires */ diff --git a/src/pages/commonPage.ts b/src/pages/commonPage.ts index 146a08ccd..40560f40f 100644 --- a/src/pages/commonPage.ts +++ b/src/pages/commonPage.ts @@ -170,13 +170,17 @@ export default class CommonPage implements CommonPageInterface { /** * Is element visible * @param page {Frame|Page} Browser tab - * @param selector {string} String to locate the element + * @param selector {string|Locator} String to locate the element * @param timeout {number} Time to wait on milliseconds before throwing an error * @returns {Promise} True if visible, false if not */ - async elementVisible(page: Frame | Page, selector: string, timeout: number = 10): Promise { + async elementVisible(page: Frame | Page, selector: string|Locator, timeout: number = 10): Promise { try { - await this.waitForVisibleSelector(page, selector, timeout); + if (typeof selector === 'string') { + await this.waitForVisibleSelector(page, selector, timeout); + } else { + await this.waitForVisibleLocator(selector, timeout); + } return true; } catch (error) { return false; @@ -416,42 +420,58 @@ export default class CommonPage implements CommonPageInterface { /** * Go to Page and wait for load State * @param page {Frame|Page} Browser tab - * @param selector {string} String to locate the element + * @param selector {string|Locator} String to locate the element * @param state {'load'|'domcontentloaded'|'networkidle'} The event to wait after click * @param timeout {number} Time to wait for navigation * @return {Promise} */ async clickAndWaitForLoadState( page: Frame | Page, - selector: string, + selector: string|Locator, state: 'load' | 'domcontentloaded' | 'networkidle' = 'networkidle', timeout: number = 30000, ): Promise { + let locator: Locator; + + if (typeof selector === 'string') { + locator = page.locator(selector); + } else { + locator = selector; + } + await Promise.all([ page.waitForLoadState(state, {timeout}), - page.locator(selector).click(), + locator.click(), ]); } /** * Go to Page and wait for change URL * @param page {Frame|Page} Browser tab - * @param selector {string} String to locate the element + * @param selector {string|Locator} String to locate the element * @param waitUntil {WaitForNavigationWaitUntil} The event to wait after click * @param timeout {number} Time to wait for navigation * @return {Promise} */ async clickAndWaitForURL( page: Frame | Page, - selector: string, + selector: string|Locator, waitUntil: WaitForNavigationWaitUntil = 'networkidle', timeout: number = 30000, ): Promise { + let locator: Locator; + + if (typeof selector === 'string') { + locator = page.locator(selector); + } else { + locator = selector; + } + const currentUrl: string = page.url(); await Promise.all([ page.waitForURL((url: URL): boolean => url.toString() !== currentUrl, {waitUntil, timeout}), - page.locator(selector).first().click(), + locator.click(), ]); } diff --git a/src/versions/1.7.2/pages/BO/login/index.ts b/src/versions/1.7.2/pages/BO/login/index.ts new file mode 100644 index 000000000..f6fc87f6a --- /dev/null +++ b/src/versions/1.7.2/pages/BO/login/index.ts @@ -0,0 +1,41 @@ +// Import pages +import type {LoginPageInterface} from '@interfaces/BO/login'; +import {Page} from '@playwright/test'; +import {LoginPage} from '@versions/1.7.8/pages/BO/login'; + +/** + * Order confirmation page, contains functions that can be used on the page + * @class + * @extends OrderConfirmationPage + */ +class LoginPageVersion extends LoginPage implements LoginPageInterface { + private readonly errorModalButton: string; + + /** + * @constructs + * Setting up texts and selectors to use on order confirmation page + */ + constructor() { + super(); + + this.submitLoginButton = 'form#login_form button[name="submitLogin"]'; + + // + this.errorModalButton = '#error-modal .modal-dialog .alert button[data-dismiss="modal"]'; + } + + /** + * Fill login form and success login + * @param page {Page} Browser tab + * @param email {string} String of employee email + * @param password {string} String of employee password + * @returns {Promise} + */ + async successLogin(page: Page, email: string, password: string): Promise { + await super.successLogin(page, email, password); + + await page.locator(this.errorModalButton).click(); + } +} + +module.exports = new LoginPageVersion(); diff --git a/src/versions/1.7.3/pages/BO/modules/moduleManager/selection.ts b/src/versions/1.7.3/pages/BO/modules/moduleManager/selection.ts new file mode 100644 index 000000000..356bec0c6 --- /dev/null +++ b/src/versions/1.7.3/pages/BO/modules/moduleManager/selection.ts @@ -0,0 +1,43 @@ +import {ModuleManagerSelectionPageInterface} from '@interfaces/BO/modules/moduleManager/selection'; +import {Page} from '@playwright/test'; +import {SelectionPage} from '@versions/1.7.4/pages/BO/modules/moduleManager/selection'; + +/** + * @class + * @extends BOBasePage + */ +class SelectionPageVersion extends SelectionPage implements ModuleManagerSelectionPageInterface { + /** + * @constructs + * Setting up titles and selectors to use on module catalog page + */ + constructor() { + super(); + + // Selectors + this.subTabSelection = '#head_tabs a.tab:nth-child(1)'; + this.subTabInstalledModules = '#head_tabs a.tab:nth-child(2)'; + } + + /** + * Go to the "Selection" tab + * @param {Page} page + * @returns {Promise} + */ + async goToTabSelection(page: Page): Promise { + await this.waitForSelectorAndClick(page, this.subTabSelection); + await this.waitForVisibleSelector(page, `${this.subTabSelection}.current`, 2000); + } + + /** + * Go to the "Installed Modules" tab + * @param {Page} page + * @returns {Promise} + */ + async goToTabInstalledModules(page: Page): Promise { + await this.waitForSelectorAndClick(page, this.subTabInstalledModules); + await this.waitForVisibleSelector(page, `${this.subTabInstalledModules}.current`, 2000); + } +} + +module.exports = new SelectionPageVersion(); diff --git a/src/versions/1.7.4/pages/BO/modules/moduleManager/index.ts b/src/versions/1.7.4/pages/BO/modules/moduleManager/index.ts new file mode 100644 index 000000000..f42d604c6 --- /dev/null +++ b/src/versions/1.7.4/pages/BO/modules/moduleManager/index.ts @@ -0,0 +1,29 @@ +// Import pages +import type {ModuleManagerPageInterface} from '@interfaces/BO/modules/moduleManager'; +import {ModuleManagerPage} from '@versions/develop/pages/BO/modules/moduleManager'; + +/** + * @class + * @extends ModuleManagerPage + */ +class ModuleManagerVersion extends ModuleManagerPage implements ModuleManagerPageInterface { + /** + * @constructs + */ + constructor() { + super(); + + this.pageTitle = 'Manage installed modules •'; + + // Modules list selectors + this.modulesListBlock = '#modules-list-container-native'; + this.allModulesBlock = `${this.modulesListBlock} .module-item-list`; + this.moduleBlock = (moduleTag: string) => `${this.allModulesBlock}[data-tech-name=${moduleTag}]`; + + // Module actions in dropdown selectors + this.actionModuleButtonInDropdownList = (action: string) => 'div.form-action-button-container.show' + + ` button.module_action_menu_${action}`; + } +} + +module.exports = new ModuleManagerVersion(); diff --git a/src/versions/1.7.4/pages/BO/modules/moduleManager/selection.ts b/src/versions/1.7.4/pages/BO/modules/moduleManager/selection.ts new file mode 100644 index 000000000..fdcca393a --- /dev/null +++ b/src/versions/1.7.4/pages/BO/modules/moduleManager/selection.ts @@ -0,0 +1,83 @@ +import {ModuleManagerSelectionPageInterface} from '@interfaces/BO/modules/moduleManager/selection'; +import BOBasePage from '@pages/BO/BOBasePage'; +import {Page} from '@playwright/test'; + +/** + * @class + * @extends BOBasePage + */ +class SelectionPage extends BOBasePage implements ModuleManagerSelectionPageInterface { + public readonly pageTitle: string; + + public readonly installMessageSuccessful: (moduleTag: string) => string; + + protected subTabSelection: string; + + protected subTabInstalledModules: string; + + private readonly searchInput: string; + + private readonly searchButton: string; + + private readonly installModuleButton: (moduleName: string) => string; + + /** + * @constructs + * Setting up titles and selectors to use on module catalog page + */ + constructor() { + super(); + + this.pageTitle = 'Module selection'; + + this.installMessageSuccessful = (moduleTag: string) => `Install action on module ${moduleTag} succeeded.`; + + // Selectors + this.subTabSelection = '#subtab-AdminModulesCatalog'; + this.subTabInstalledModules = '#subtab-AdminModulesManage'; + this.searchInput = '#search-input-group input.pstaggerAddTagInput'; + this.searchButton = '#module-search-button'; + this.installModuleButton = (moduleTag: string) => `div[data-tech-name="${moduleTag}"] button.module_action_menu_install`; + } + + /* + Methods + */ + /** + * Go to the "Selection" tab + * @param {Page} page + * @returns {Promise} + */ + async goToTabSelection(page: Page): Promise { + await this.waitForSelectorAndClick(page, this.subTabSelection); + await this.waitForVisibleSelector(page, `${this.subTabSelection}.active`, 2000); + } + + /** + * Go to the "Selection" tab + * @param {Page} page + * @returns {Promise} + */ + async goToTabInstalledModules(page: Page): Promise { + await this.waitForSelectorAndClick(page, this.subTabInstalledModules); + await this.waitForVisibleSelector(page, `${this.subTabInstalledModules}.active`, 2000); + } + + /** + * Install the module and return if installed + * @param {Page} page + * @param {string} moduleTag + * @returns {Promise} + */ + async installModule(page: Page, moduleTag: string): Promise { + await page.locator(this.searchInput).fill(moduleTag); + await page.locator(this.searchButton).click(); + await this.elementVisible(page, this.installModuleButton(moduleTag), 3000); + await page.locator(this.installModuleButton(moduleTag)).click(); + + return this.elementNotVisible(page, this.installModuleButton(moduleTag), 3000); + } +} + +const selectionPage = new SelectionPage(); +export {selectionPage, SelectionPage}; diff --git a/src/versions/1.7.8/pages/BO/login/index.ts b/src/versions/1.7.8/pages/BO/login/index.ts index eb56ae0ee..2b8b1ee23 100644 --- a/src/versions/1.7.8/pages/BO/login/index.ts +++ b/src/versions/1.7.8/pages/BO/login/index.ts @@ -8,7 +8,7 @@ import {LoginPage} from '@versions/8.1/pages/BO/login'; * @class * @extends OrderConfirmationPage */ -class Login extends LoginPage implements LoginPageInterface { +class LoginPageVersion extends LoginPage implements LoginPageInterface { private readonly onboardingCloseButton: string; private readonly onboardingStopButton: string; @@ -50,4 +50,5 @@ class Login extends LoginPage implements LoginPageInterface { } } -module.exports = new Login(); +const loginPage = new LoginPageVersion(); +export {loginPage, LoginPageVersion as LoginPage}; diff --git a/src/versions/8.1.0/pages/FO/classic/product/index.ts b/src/versions/8.1.0/pages/FO/classic/product/index.ts new file mode 100644 index 000000000..ebe43668e --- /dev/null +++ b/src/versions/8.1.0/pages/FO/classic/product/index.ts @@ -0,0 +1,37 @@ +import type {FoProductPageInterface} from '@interfaces/FO/product/index'; +import type {Page} from '@playwright/test'; +import {ProductPage} from '@versions/develop/pages/FO/classic/product/index'; + +/** + * @class + * @extends ProductPage + */ +class ProductPageVersion extends ProductPage implements FoProductPageInterface { + private readonly productCategoryProductsBlock: string; + + /** + * @constructs + * Setting up texts and selectors to use on order confirmation page + */ + constructor(theme: string = 'classic') { + super(theme); + + // Selectors + this.productCategoryProductsBlock = '#content-wrapper section.featured-products'; + } + + /** + * Has products block + * @param blockName {'categoryproducts'} The block name in the page + * @param page {Page} Browser tab + * @return {Promise} + */ + async hasProductsBlock(page: Page, blockName: 'categoryproducts'): Promise { + if (blockName === 'categoryproducts') { + return (await page.locator(this.productCategoryProductsBlock).count()) > 0; + } + return false; + } +} + +module.exports = new ProductPageVersion(); diff --git a/src/versions/develop/pages/BO/login/index.ts b/src/versions/develop/pages/BO/login/index.ts index 45525efd2..8a42c9122 100644 --- a/src/versions/develop/pages/BO/login/index.ts +++ b/src/versions/develop/pages/BO/login/index.ts @@ -32,7 +32,7 @@ class LoginPage extends BOBasePage implements LoginPageInterface { private readonly passwordInput: string; - private readonly submitLoginButton: string; + protected submitLoginButton: string; protected alertDangerDiv: string; diff --git a/src/versions/develop/pages/BO/modules/moduleManager/index.ts b/src/versions/develop/pages/BO/modules/moduleManager/index.ts index 33a0d64d5..1d83dd4bd 100644 --- a/src/versions/develop/pages/BO/modules/moduleManager/index.ts +++ b/src/versions/develop/pages/BO/modules/moduleManager/index.ts @@ -55,7 +55,7 @@ class ModuleManagerPage extends BOBasePage implements ModuleManagerPageInterface private readonly bulkActionsModalConfirmButton: string; - private readonly modulesListBlock: string; + protected modulesListBlock: string; private readonly modulesListBlockTitle: string; @@ -81,7 +81,7 @@ class ModuleManagerPage extends BOBasePage implements ModuleManagerPageInterface private readonly actionsDropdownButton: (moduleTag: string) => string; - private readonly actionModuleButtonInDropdownList: (action: string) => string; + protected actionModuleButtonInDropdownList: (action: string) => string; private readonly modalConfirmAction: (moduleTag: string, action: string) => string; @@ -446,7 +446,7 @@ class ModuleManagerPage extends BOBasePage implements ModuleManagerPageInterface if (cancel) { await this.waitForSelectorAndClick(page, this.modalConfirmCancel(module.tag, action)); - await this.elementNotVisible(page, this.modalConfirmAction(module.tag, action), 10000); + await this.waitForHiddenSelector(page, this.modalConfirmAction(module.tag, action), 10000); return ''; } if (action === 'uninstall' && forceDeletion) { diff --git a/src/versions/mock/pages/BO/modules/moduleManager/selection.ts b/src/versions/mock/pages/BO/modules/moduleManager/selection.ts new file mode 100644 index 000000000..a4bfdd2f9 --- /dev/null +++ b/src/versions/mock/pages/BO/modules/moduleManager/selection.ts @@ -0,0 +1,53 @@ +import {ModuleManagerSelectionPageInterface} from '@interfaces/BO/modules/moduleManager/selection'; +import BOBasePage from '@pages/BO/BOBasePage'; + +/** + * Mock Page for unsupported version + * @class + * @extends BOBasePage + */ +class SelectionPageMock extends BOBasePage implements ModuleManagerSelectionPageInterface { + public readonly pageTitle: string; + + public readonly installMessageSuccessful: (moduleTag: string) => string; + + /** + * @constructs + * Setting up titles and selectors to use on module catalog page + */ + constructor() { + super(); + + this.pageTitle = ''; + this.installMessageSuccessful = () => ''; + } + + /* + Methods + */ + /** + * Go to the "Selection" tab + * @returns {Promise} + */ + async goToTabSelection(): Promise { + // do nothing. + } + + /** + * Go to the "Installed Modules" tab + * @returns {Promise} + */ + async goToTabInstalledModules(): Promise { + // do nothing. + } + + /** + * Install the module and return if installed + * @returns {Promise} + */ + async installModule(): Promise { + return true; + } +} + +module.exports = new SelectionPageMock();