From e53c10af20e5826c2c777d3d1fadceb4dff86050 Mon Sep 17 00:00:00 2001 From: sgauruseu Date: Fri, 18 Oct 2024 19:00:01 +0300 Subject: [PATCH] ui-tests issue #1390 --- testing/libs/WebDriverHelper.js | 6 +- testing/libs/app_const.js | 16 + testing/libs/elements.js | 338 ++++++++------ testing/libs/project.utils.js | 34 +- testing/libs/studio.utils.js | 249 +++++++---- .../archive/archive.browse.panel.js | 8 +- .../archive/archive.delete.dialog.js | 2 +- .../archive/archive.filter.panel.js | 12 +- .../archive/archive.restore.dialog.js | 4 +- .../archive/archive.widget.item.view.js | 6 +- testing/page_objects/base.browse.panel.js | 53 ++- .../browsepanel/content.browse.panel.js | 413 ++++++++++-------- .../browsepanel/content.filter.panel.js | 357 +++++++++++++-- .../browsepanel/contentItem.preview.panel.js | 96 +++- .../browse.dependencies.widget.js | 13 +- .../detailspanel/browse.details.panel.js | 5 + .../detailspanel/browse.versions.widget.js | 45 +- .../detailspanel/content.widget.item.view.js | 4 +- .../properties.widget.itemview.js | 2 +- .../browsepanel/new.content.dialog.js | 2 +- .../compare.content.versions.dialog.js | 36 +- .../page_objects/components/datetime.range.js | 121 +++-- testing/page_objects/components/htmlarea.js | 31 +- .../projects/extended.principal.combobox.js | 4 +- .../project.access.control.combobox.js | 4 +- .../projects/project.applications.combobox.js | 4 +- .../components/projects/projects.combobox.js | 21 +- .../components/selectors/base.dropdown.js | 40 +- .../selectors/compare.versions.dropdown.js | 4 +- .../selectors/custom.selector.combobox.js | 42 -- .../components/selectors/fragment.dropdown.js | 41 -- .../selectors/image.selector.dropdown.js | 14 +- .../inspect.panel.controller.selector.js | 4 +- .../selectors/locale.selector.dropdown.js | 6 +- .../selectors/page.descriptor.dropdown.js | 4 +- .../selectors/principal.combobox.dropdown.js | 39 ++ .../selectors/widget.selector.dropdown.js | 4 +- .../page_objects/components/text.component.js | 183 -------- .../confirm.content.delete.dialog.js | 10 +- testing/page_objects/confirmation.mask.js | 2 - .../page_objects/content.publish.dialog.js | 9 +- testing/page_objects/delete.content.dialog.js | 137 +++--- .../details_panel/base.dependencies.widget.js | 60 ++- .../details_panel/base.details.panel.js | 29 +- .../details_panel/base.layers.widget.js | 75 ++-- .../base.publish.report.widget.js | 12 +- .../details_panel/base.versions.widget.js | 263 +++++++++-- .../compare.content.versions.dialog.js | 151 ------- .../details_panel/create.variant.dialog.js | 6 +- .../details_panel/edit.settings.dialog.js | 41 +- .../page_objects/edit.permissions.dialog.js | 69 ++- testing/page_objects/page.js | 51 ++- .../project/layers.content.tree.dialog.js | 24 +- .../project.wizard.access.mode.step.js | 7 +- .../project.wizard.dialog.js | 51 ++- .../project.wizard.language.step.js | 2 +- .../project.wizard.parent.project.step.js | 40 +- .../project.wizard.permissions.step.js | 2 +- .../project/project.wizard.panel.js | 201 +++++---- .../project/settings.browse.panel.js | 133 +++--- testing/page_objects/publish.report.dialog.js | 20 +- .../wizardpanel/content.wizard.panel.js | 70 ++- testing/specs/archive.browse.panel.spec.js | 2 + .../layers.widget.localize.button.spec.js | 3 +- testing/wdio.chrome.conf.js | 2 +- 65 files changed, 2186 insertions(+), 1553 deletions(-) delete mode 100644 testing/page_objects/components/selectors/custom.selector.combobox.js delete mode 100644 testing/page_objects/components/selectors/fragment.dropdown.js create mode 100644 testing/page_objects/components/selectors/principal.combobox.dropdown.js delete mode 100644 testing/page_objects/components/text.component.js delete mode 100644 testing/page_objects/details_panel/compare.content.versions.dialog.js diff --git a/testing/libs/WebDriverHelper.js b/testing/libs/WebDriverHelper.js index 8e8f593a..5f465553 100644 --- a/testing/libs/WebDriverHelper.js +++ b/testing/libs/WebDriverHelper.js @@ -43,13 +43,13 @@ WebDriverHelper.prototype.setupBrowser = function setupBrowser(w, h) { console.log('browser name ##################### ' + browser_name); console.log('browser width ##################### ' + width); let options = { - logLevel: "error", - automationProtocol: "webdriver", - "wdio:enforceWebDriverClassic": true, + logLevel: 'error', + automationProtocol: 'webdriver', capabilities: { "wdio:enforceWebDriverClassic": true, browserName: browser_name, browserVersion: browser_version, + "wdio:enforceWebDriverClassic": true, 'goog:chromeOptions': makeChromeOptions(isHeadless, width, height) } }; diff --git a/testing/libs/app_const.js b/testing/libs/app_const.js index 7e53fe82..88c45e56 100644 --- a/testing/libs/app_const.js +++ b/testing/libs/app_const.js @@ -379,4 +379,20 @@ module.exports = Object.freeze({ ARCHIVED: 'Archived', ARCHIVED_BY: 'Archived by', }, + WIDGET_SELECTOR_OPTIONS: { + VERSION_HISTORY: 'Version history', + DEPENDENCIES: 'Dependencies', + LAYERS: 'Layers', + EMULATOR: 'Emulator', + DETAILS: 'Details' + }, + BROWSER_TITLES: { + CONTENT_STUDIO: 'Content Studio - Enonic XP Admin', + XP_HOME: 'Enonic XP Home', + }, + ACCESSIBILITY_ATTRIBUTES: { + ROLE: 'role', + ARIA_LABEL: 'aria-label', + ARIA_HAS_POPUP: 'aria-haspopup', + }, }); diff --git a/testing/libs/elements.js b/testing/libs/elements.js index ba3806a7..c5f28517 100644 --- a/testing/libs/elements.js +++ b/testing/libs/elements.js @@ -1,55 +1,191 @@ /** * Created on 02.12.2017. */ - module.exports = Object.freeze({ NOTIFICATION_TEXT: "//div[@class='notification-text']", + BUTTON_WITH_SPAN_ADD: "//button[child::span[text()='Add']]", FORM_VIEW: `//div[contains(@id,'FormView')]`, FORM_ITEM: "//div[contains(@id,'FormItem')]", DATE_TIME_PICKER_INPUT: "//div[contains(@id,'DateTimePicker')]//input[contains(@id,'TextInput')]", TIME_PICKER_INPUT: "//div[contains(@id,'TimePicker')]//input[contains(@id,'TextInput')]", - DATE_PICKER_INPUT: "//div[contains(@id,'DatePicker') and @class='date-picker']//input[contains(@id,'TextInput')]", - CONTENT_SELECTOR: "//div[contains(@id,'ContentSelector')]", + DATE_PICKER_INPUT: "//div[contains(@id,'DatePicker') and contains(@class,'date-time-picker')]//input[contains(@id,'TextInput')]", + CONTENT_COMBOBOX: "//div[contains(@id,'ContentComboBox')]", SELECTED_LOCALE: `//div[contains(@id,'LocaleSelectedOptionView')]`, - NAMES_VIEW_BY_NAME: "//div[contains(@id,'NamesView') and child::p[contains(@class,'sub-name') and contains(.,'%s')]]", - NAMES_VIEW_BY_DISPLAY_NAME: "//div[contains(@id,'NamesView') and child::h6[contains(@class,'main-name') and contains(.,'%s')]]", - SLICK_VIEW_PORT: `//div[contains(@class,'slick-viewport')]`, - SLICK_ROW: "//div[contains(@class,'slick-viewport')]//div[contains(@class,'slick-row')]", H6_DISPLAY_NAME: "//div[contains(@id,'NamesView')]//h6[contains(@class,'main-name')]", P_SUB_NAME: "//p[contains(@class,'sub-name')]", - RICH_TEXT_EDITOR: `//div[contains(@id,'TextComponentView') and contains(@class,'editor-focused')]//div[contains(@id,'TextComponentView')]`, + RICH_TEXT_EDITOR: `//div[contains(@id,'TextComponentView') and contains(@class,'editor-focused')]`, TEXT_AREA: "//textarea[contains(@id,'TextArea')]", + WIDGET_SELECTOR_DROPDOWN: `//div[contains(@id,'WidgetSelectorDropdown')]`, DROP_DOWN_HANDLE: "//button[contains(@id,'DropdownHandle')]", - GRID_CANVAS: `//div[contains(@class,'grid-canvas')]`, SELECTION_PANEL_TOGGLER: `//button[contains(@id,'SelectionPanelToggler')]`, TEXT_INPUT: "//input[@type='text']", DROPDOWN_OPTION_FILTER_INPUT: "//input[contains(@id,'DropdownOptionFilterInput')]", + OPTION_FILTER_INPUT: "//input[contains(@id,'OptionFilterInput') and contains(@class, 'option-filter-input')]", VALIDATION_RECORDING_VIEWER: "//div[contains(@id,'ValidationRecordingViewer')]//li", CONTENT_SUMMARY_AND_STATUS_VIEWER: "//div[contains(@id,'ContentSummaryAndCompareStatusViewer')]", - OPTION_SET_MENU_BUTTON: "//button[contains(@id,'MoreButton')]", validationRecording: "//div[contains(@id,'ValidationRecordingViewer')]//li", - inputView: "//div[contains(@id,'InputView')]", INPUT_VALIDATION_VIEW: "//div[contains(@id,'InputViewValidationViewer')]", OCCURRENCE_ERROR_BLOCK: "//div[contains(@id,'InputOccurrenceView')]//div[contains(@class,'error-block')]", + OCCURRENCE_VIEW: "//div[contains(@id,'InputOccurrenceView')]", + ADD_NEW_CONTENT_BUTTON: "//button[contains(@id,'NewContentButton')]", + EDIT_ICON: "//a[@class='edit']", NUMBER_IN_SELECTION_TOGGLER: `//button[contains(@id,'SelectionPanelToggler')]/span`, - checkBoxDiv: label => `//div[contains(@id,'Checkbox') and child::label[contains(.,'${label}')]]`, - radioButtonByLabel: label => { - return `//span[contains(@class,'radio-button') and child::label[text()='${label}']]//input` + CONTENT_SELECTOR: { + DIV: "//div[contains(@id,'ContentSelector')]", + selectedOptionByName: option => { + return `//div[contains(@id,'ContentSelectedOptionView') and descendant::h6[contains(@class,'main-name') and text()='${option}']]` + } + }, + FORM_VIEW_PANEL: { + INPUT_VIEW: "//div[contains(@id,'InputView')]", + HTML_AREA_INPUT: "//div[contains(@id,'InputView') and descendant::div[contains(@id,'HtmlArea')]]", + TEXT_LINE_INPUT: "//div[contains(@id,'InputView') and descendant::div[contains(@id,'TextLine')]]", + COMBOBOX_INPUT: "//div[contains(@id,'InputView') and descendant::div[contains(@id,'ComboBox')]]", + }, + COMBOBOX: { + MODE_TOGGLER_BUTTON: "//button[contains(@id,'ModeTogglerButton')]", + APPLY_SELECTION_BUTTON: "//button[contains(@class,'apply-selection-button')]", + }, + INPUTS: { + TEXT_INPUT: "//input[@type='text']", + CHECKBOX_INPUT: "//input[@type='checkbox']", + DROPDOWN_OPTION_FILTER_INPUT: "//input[contains(@id,'DropdownOptionFilterInput')]", + }, + DIV: { + FRAGMENT_DROPDOWN_DIV: `//div[contains(@id,'FragmentDropdown')]`, + CHECKBOX_DIV: "//div[contains(@id,'Checkbox')]", + DROPDOWN_DIV: "//div[contains(@id,'Dropdown')]", + NOTIFICATION_ACTIONS_DIV: "//div[@class='notification-actions']", + CONTENT_APP_BAR_DIV: "//div[contains(@id,'ContentAppBar')]", + PROJECT_VIEWER_DIV: "//div[contains(@id,'ProjectViewer')]", + CONTENT_SUMMARY_AND_STATUS_VIEWER: "//div[contains(@id,'ContentSummaryAndCompareStatusViewer')]", + SHOW_ENTIRE_CONTENT_CHECKBOX_DIV: "//div[contains(@id,'Checkbox') and child::label[text()='Show entire content']]", + }, + DATE_PICKER: { + fromDateInput: "//div[contains(@id,'DatePicker') and preceding-sibling::label[text()='From']]//input[contains(@id,'TextInput')]", + toDateInput: "//div[contains(@id,'DatePicker') and preceding-sibling::label[text()='To']]//input[contains(@id,'TextInput')]", + }, + BUTTONS: { + ARCHIVE_BUTTON: "//button[contains(@id,WidgetButton) and @title='Archive']", + PUBLISH_REPORT_GENERATE: "//button[contains(@class,'widget-publish-report-button')]", + BUTTON_WITH_SPAN_ADD: "//button[child::span[text()='Add']]", + NEW_CONTENT_BUTTON: "//button[contains(@class,'new-content-button')]", + REFRESH_BUTTON: "//button[contains(@class,'icon-loop')]", + DROP_DOWN_HANDLE: "//button[contains(@id,'DropdownHandle')]", + SELECTION_PANEL_TOGGLER: `//button[contains(@id,'SelectionPanelToggler')]`, + SELECTOR_MODE_TOGGLER: "//button[contains(@id,'ModeTogglerButton')]", + UPLOAD_BUTTON: "//button[contains(@class,'upload-button')]", + actionButton: (label) => `//button[contains(@id,'ActionButton') and child::span[contains(.,'${label}')]]`, + button: (label, cssValue) => `//button[contains(@class,'${cssValue}') and child::span[contains(.,'${label}')]]`, + dialogButton: label => `//button[contains(@id,'DialogButton') and child::span[contains(.,'${label}')]]`, + dialogButtonStrict: label => `//button[contains(@id,'DialogButton') and child::span[text()='${label}']]`, + togglerButton: (label) => `//button[contains(@id,'TogglerButton') and child::span[text()='${label}']]`, + COLLAPSE_BUTTON_BOTTOM: "//div[contains(@class,'bottom-button-row')]//a[contains(@class,'collapse-button') and (text()='Collapse' or text()='Collapse all')]", + COLLAPSE_ALL_BUTTON_BOTTOM: "//div[contains(@class,'bottom-button-row')]//a[contains(@class,'collapse-button') and (text()='Collapse' or text()='Collapse all')]", + EXPAND_BUTTON_BOTTOM: "//div[contains(@class,'bottom-button-row')]//a[contains(@class,'collapse-button') and text()='Expand']", + EXPAND_ALL_BUTTON_BOTTOM: "//div[contains(@class,'bottom-button-row')]//a[contains(@class,'collapse-button') and text()='Expand all')]", + COLLAPSE_BUTTON_TOP: "//div[contains(@class,'top-button-row')]//a[contains(@class,'collapse-button') and (text()='Collapse' or text()='Collapse all')]", + MORE_BUTTON: "//button[contains(@id,'MoreButton')]", + ADD_BUTTON: "//div[contains(@class,'bottom-button-row')]//button[child::span[text()='Add']]", + }, + CONTENT_SELECTOR: { + DIV: "//div[contains(@id,'ContentSelector')]", + selectedOptionByName: option => { + return `//div[contains(@id,'ContentSelectedOptionView') and descendant::h6[contains(@class,'main-name') and text()='${option}']]` + } + }, + FORM_VIEW_PANEL: { + INPUT_VIEW: "//div[contains(@id,'InputView')]", + HTML_AREA_INPUT: "//div[contains(@id,'InputView') and descendant::div[contains(@id,'HtmlArea')]]", + TEXT_LINE_INPUT: "//div[contains(@id,'InputView') and descendant::div[contains(@id,'TextLine')]]", + COMBOBOX_INPUT: "//div[contains(@id,'InputView') and descendant::div[contains(@id,'ComboBox')]]", + }, + DROPDOWN_SELECTOR: { + contentListElementByDisplayName: (container, displayName) => { + return container + + `//li[contains(@id,'ContentListElement') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]`; + }, + // non-clickable li element in options dropdown list, it is for checking read-only status + contentListElementByName: (container, name) => { + return container + + `//li[contains(@id,'ContentListElement') and descendant::p[contains(@class,'sub-name') and contains(.,'${name}')]]`; + }, + listItemByDisplayName: (itemName) => { + return `//li[contains(@class,'item-view-wrapper') and descendant::h6[contains(.,'${itemName}')]]` + }, + // clickable option in dropdown options list + dropdownListItemByDisplayName: (container, displayName) => { + return container + + `//*[contains(@class,'item-view-wrapper')]//h6[contains(@class,'main-name') and contains(.,'${displayName}')]`; + }, + dropdownListItemByName: (container, name) => { + return container + + `//*[contains(@class,'item-view-wrapper')]//p[contains(@class,'sub-name') and contains(.,'${name}')]`; + }, + flatModeDropdownImgItemByDisplayName: (container, displayName) => { + return container + + `//*[contains(@class,'item-view-wrapper') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]//img`; + }, + IMG_DROPDOWN_OPT_DISPLAY_NAME_FLAT_MODE: "//li[contains(@class,'item-view-wrapper')]" + + "//div[contains(@id,'NamesView')]//h6[contains(@class,'main-name')]", + OPTIONS_LI_ELEMENT: "//li[contains(@id,'ContentListElement')]", + DROPDOWN_HANDLE: "//button[contains(@id,'DropdownHandle')]", + OPTION_FILTER_INPUT: "//input[contains(@id,'OptionFilterInput') and contains(@class, 'option-filter-input')]", + MODE_TOGGLER_BUTTON: "//button[contains(@id,'ModeTogglerButton')]", + APPLY_SELECTION_BUTTON: "//button[contains(@class,'apply-selection-button')]", + CONTENT_TREE_SELECTOR: "//div[contains(@id,'ContentTreeSelectorDropdown')]", + CONTENTS_TREE_LIST_UL: "//ul[contains(@id,'ContentsTreeList')]", + DROPDOWN_LIST_ITEM: "//*[contains(@class,'item-view-wrapper')]", + DROPDOWN_DIV_ITEM: "//div[contains(@class,'item-view-wrapper')]", + WIDGET_FILTER_DROPDOWN: `//div[contains(@id,'WidgetFilterDropdown')]`, + FILTERABLE_LISTBOX: "//div[contains(@id,'FilterableListBoxWrapper')]", + IMAGE_CONTENT_COMBOBOX_DIV: "//div[contains(@id,'ImageContentComboBox')]", + }, + + DEPENDANTS: { + EDIT_ENTRY: "//div[contains(@id,'DialogStateEntry') and contains(@class,'edit-entry')]", + DEPENDANTS_BLOCK: "//div[contains(@class, 'dependants') and descendant::span[contains(@class,'dependants-title') and text()='Dependencies']]", + DEPENDENT_ITEM_LIST_UL: "//ul[contains(@id,'DialogDependantItemsList')]", + DEPENDENT_ITEM_LIST_UL_2: "//ul[contains(@id,'PublishDialogDependantList')]", + DEPENDANT_ITEM_VIEWER: "//div[contains(@id,'DependantItemViewer')]", + DEPENDANT_ITEM_LIST_UNPUBLISH_DIALOG: "//ul[contains(@id,'DialogWithRefsDependantList')]", }, - tabBarItemByName(name) { + tabBarItemByName: name => { return `//li[contains(@id,'TabBarItem') and child::a[text()='${name}']] ` }, - slickRowByDisplayName: (container, displayName) => { - return container + - `//div[contains(@class,'slick-viewport')]//div[contains(@class,'slick-row') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]`; + + TREE_GRID: { + CONTENT_STATUS: "//div[contains(@id,'StatusBlock')]/span", + SORT_DIALOG_TOGGLE: "//div[contains(@class,'sort-dialog-trigger')]", + EXPANDER_ICON_DIV: "//div[contains(@class,'toggle icon-arrow_drop_up')]", + itemByName: name => { + return `//div[contains(@id,'NamesView') and child::p[contains(@class,'xp-admin-common-sub-name') and contains(.,'${name}')]]` + }, + contentSummaryByDisplayName: (parent, displayName) => { + return `//div[contains(@id,'ContentSummaryListViewer') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]` + }, + contentSummaryByName: name => { + return `//div[contains(@id,'ContentSummaryListViewer') and descendant::p[contains(@class,'sub-name') and contains(.,'${name}')]]` + }, + itemTreeGridListElementByDisplayName: displayName => {//ContentTreeGridListViewer + return `(//li[contains(@id,'ContentsTreeGridListElement') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]])[last()]` + }, + itemTreeGridListElementByName: name => { + return `//li[contains(@id,'ContentsTreeGridListElement') and descendant::p[contains(@class,'sub-name') and contains(.,'${name}')]]` + }, + archiveItemTreeGridListElementByDisplayName: displayName => { + return `(//li[contains(@id,'ArchiveTreeListElement') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]])[last()]` + }, + archiveItemTreeGridListElementByName: name => { + return `(//li[contains(@id,'ArchiveTreeListElement') and descendant::p[contains(@class,'sub-name') and contains(.,'${name}')]])[last()]` + }, }, + checkBoxDiv: label => `//div[contains(@id,'Checkbox') and child::label[contains(.,'${label}')]]`, actionButton: (label) => `//button[contains(@id,'ActionButton') and child::span[contains(.,'${label}')]]`, actionButtonStrict: (label) => `//button[contains(@id,'ActionButton') and child::span[text()='${label}']]`, - dialogButton: label => `//button[contains(@id,'DialogButton') and child::span[text()='${label}']]`, - slickRowByName: (container, displayName) => { - return container + - `//div[contains(@class,'slick-viewport')]//div[contains(@class,'slick-row') and descendant::p[contains(@class,'sub-name') and contains(.,'${displayName}')]]`; - }, + dialogButton: label => `//button[contains(@id,'DialogButton') and child::span[contains(.,'${label}')]]`, + dialogButtonStrict: label => `//button[contains(@id,'DialogButton') and child::span[text()='${label}']]`, + togglerButton: (label) => `//button[contains(@id,'TogglerButton') and child::span[text()='${label}']]`, itemByDisplayName: displayName => { return `//div[contains(@id,'NamesView') and child::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]` }, @@ -59,21 +195,24 @@ module.exports = Object.freeze({ itemByName: name => { return `//div[contains(@id,'NamesView') and child::p[contains(@class,'xp-admin-common-sub-name') and contains(.,'${name}')]]` }, - projectByName: name => { - return `//div[contains(@id,'NamesView') and descendant::span[contains(@class,'name') and contains(.,'${name}')]]` + itemStrictByName: name => { + return `//div[contains(@id,'NamesView') and child::p[contains(@class,'xp-admin-common-sub-name') and text()='${name}']]` }, + formItemByLabel: (label) => { return `//div[contains(@id,'FormItem') and descendant::label[contains(.,'${label}')]]` }, - expanderIconByName: name => { - return `//div[contains(@id,'NamesView') and child::p[contains(@class,'xp-admin-common-sub-name') and contains(.,'${name}')]]` + - `/ancestor::div[contains(@class,'slick-cell')]/span[contains(@class,'collapse') or contains(@class,'expand')]`; + + EMPTY_OPTIONS_H5: "//h5[contains(@class,'empty-list-item') and text()='No matching items']", + radioButtonByLabel: label => { + return `//span[contains(@class,'radio-button') and child::label[text()='${label}']]//input` }, - EMPTY_OPTIONS_DIV: "//div[contains(@class,'empty-options') and text()='No matching items']", tabMenuItem: menuName => `//li[contains(@id,'TabMenuItem') and child::a[text()='${menuName}']]`, TREE_GRID_CONTEXT_MENU: "//ul[contains(@id,'TreeGridContextMenu')]", - CANCEL_BUTTON_TOP: `//div[@class='cancel-button-top']`, - CANCEL_BUTTON_DIALOG: `//button[contains(@id,'DialogButton') and child::span[text()='Cancel']]`, + SELECTOR_MODE_TOGGLER: "//button[contains(@id,'ModeTogglerButton')]", + CANCEL_BUTTON_TOP: "//div[@class='cancel-button-top']", + UPLOAD_BUTTON: "//button[contains(@class,'upload-button')]", + MORE_FOLD_BUTTON: "//div[contains(@id,'FoldButton') and descendant::span[text()='More']]", COMBO_BOX_OPTION_FILTER_INPUT: "//input[contains(@id,'ComboBoxOptionFilterInput')]", CONTENT_WIZARD_STEP_FORM: "//div[contains(@id,'ContentWizardStepForm')]", BASE_SELECTED_OPTION: "//div[contains(@id,'BaseSelectedOptionView')]", @@ -90,24 +229,23 @@ module.exports = Object.freeze({ CHECKBOX_INPUT: "//input[@type='checkbox']", CONTENT_SELECTED_OPTION_VIEW: "//div[contains(@id,'ContentSelectedOptionView')]", DETAILS_PANEL_TOGGLE_BUTTON: `//button[contains(@id,'NonMobileContextPanelToggleButton')]`, - ACTION_BUTTON: `//button[contains(@id,'ActionButton')]`, - ADD_BUTTON: "//div[contains(@class,'bottom-button-row')]//button[child::span[text()='Add']]", + SHOW_CONTEXT_PANEL_BUTTON: "//button[contains(@id,'NonMobileContextPanelToggleButton') and @title='Show Context Panel']", SHOW_DEPENDENT_ITEM_LINK: `//h6[@class='dependants-header' and contains(.,'Show dependent items')]`, - COMPARE_WITH_CURRENT_VERSION: `//button[contains(@id,'ActionButton') and @title='Compare with current version']`, - LIVE_EDIT_FRAME: "//iframe[contains(@class,'live-edit-frame shown')]", + VERSIONS_SHOW_CHANGES_BUTTON: `//button[contains(@id,'ActionButton') and @title='Show changes']`, + LIVE_EDIT_FRAME: "//iframe[contains(@class,'live-edit-frame')]", APP_MODE_SWITCHER_TOGGLER: "//div[contains(@id,'AppWrapper')]//button[contains(@id,'ToggleIcon')]", - SETTINGS_BUTTON: "//button[contains(@id,WidgetButton) and @title='Settings']", - ARCHIVE_BUTTON: "//button[contains(@id,WidgetButton) and @title='Archive']", - MODE_CONTENT_BUTTON: "//button[contains(@id,WidgetButton) and @title='Content']", - SHOW_ENTIRE_CONTENT_CHECKBOX_DIV: "//div[contains(@id,'Checkbox') and child::label[text()='Show entire content']]", - DATE_PICKER:{ - fromDateInput:"//div[contains(@id,'DatePicker') and preceding-sibling::label[text()='From']]//input[contains(@id,'TextInput')]", - toDateInput: "//div[contains(@id,'DatePicker') and preceding-sibling::label[text()='To']]//input[contains(@id,'TextInput')]", + SETTINGS_BUTTON: "//button[contains(@id,'WidgetButton') and child::span[text()='Settings']]", + MODE_CONTENT_BUTTON: "//button[contains(@id,'WidgetButton') and @title='Content']", + + PUBLISH_DIALOG: { + EXCLUDE_BTN: "//button[child::span[contains(.,'Exclude')]]", }, CKE: { + TEXTAREA_DIV: "//div[contains(@id,'cke_TextArea')]", insertTableButton: `//a[contains(@class,'cke_button') and contains(@title,'Table')]`, insertLinkButton: `//a[contains(@class,'cke_button') and contains(@title,'Link')]`, insertAnchorButton: `//a[contains(@class,'cke_button') and @title='Anchor']`, + findAndReplaceButton: "//a[contains(@class,'cke_button') and @title='Find and replace']", insertImageButton: `//a[contains(@class,'cke_button') and contains(@title,'Image')]`, insertMacroButton: `//a[contains(@class,'cke_button') and @title='Insert macro']`, insertSpecialCharacter: "//a[contains(@class,'cke_button') and @title='Insert Special Character']", @@ -124,14 +262,28 @@ module.exports = Object.freeze({ justifyButton: `//a[contains(@class,'cke_button') and contains(@title,'Justify')]`, bulletedButton: `//a[contains(@class,'cke_button') and contains(@title,'Bulleted List')]`, numberedButton: `//a[contains(@class,'cke_button') and contains(@title,'Numbered List')]`, - sourceButton: `//a[contains(@class,'cke_button__sourcedialog') and contains(@href,'Source')]`, - fullScreen: `//a[contains(@class,'cke_button__fullscreen') and contains(@href,'Fullscreen')]`, + sourceButton: `//a[contains(@class,'cke_button__sourcedialog') and @title='Source']`, + fullScreen: `//a[contains(@class,'cke_button__fullscreen') and @title='Fullscreen']`, tableButton: `//a[contains(@class,'cke_button') and contains(@title,'Table')]`, + finAndReplaceButton: `//a[contains(@class,'cke_button') and contains(@title,'Find and replace')]`, strikethroughButton: `//a[contains(@class,'cke_button') and contains(@title,'Strikethrough')]`, increaseIndentButton: `//a[contains(@class,'cke_button') and contains(@title,'Increase Indent')]`, decreaseIndentButton: `//a[contains(@class,'cke_button') and contains(@title,'Decrease Indent')]`, formatDropDownHandle: `//span[contains(@class,'cke_combo__styles') and descendant::a[@class='cke_combo_button']]`, }, + PROJECTS: { + projectNameAndIconViewDiv: displayName => `//div[contains(@id,'NamesAndIconView') and descendant::span[contains(@class,'display-name') and contains(.,'${displayName}')]]`, + projectByName: name => { + return `//div[contains(@id,'ProjectItemViewer') and descendant::h6[contains(@class,'main-name') and contains(.,'${name}')]]` + }, + projectByIdentifier: id => { + return `//div[contains(@id,'NamesView') and descendant::p[contains(@class,'sub-name') and contains(.,'${id}')]]` + }, + selectedProjectView: displayName => `//div[contains(@id,'ProjectApplicationSelectedOptionView') and descendant::h6[text()='${displayName}']]`, + }, + INSPECT_PANEL: { + DESCRIPTOR_VIEWER_DIV: "//div[contains(@id,'DescriptorViewer')]", + }, FILTER_PANEL: { clearFilterLink: "//a[contains(@id,'ClearFilterButton')]", searchInput: "//input[contains(@id,'TextSearchField')]", @@ -146,102 +298,4 @@ module.exports = Object.freeze({ aggregationGroupDiv: name => `//div[contains(@id,'AggregationGroupView') and child::h2[text()='${name}']]`, aggregationDropdown: label => `//div[contains(@id,'FilterableAggregationGroupView') and child::h2[text()='${label}']]//div[contains(@id,'SelectableListBoxDropdown')]`, }, - DEPENDANTS: { - EDIT_ENTRY: "//div[contains(@id,'DialogStateEntry') and contains(@class,'edit-entry')]", - DEPENDANTS_BLOCK: "//div[contains(@class, 'dependants') and descendant::span[contains(@class,'dependants-title') and text()='Dependencies']]", - DEPENDENT_ITEM_LIST_UL: "//ul[contains(@id,'DialogDependantItemsList')]", - DEPENDENT_ITEM_LIST_UL_2: "//ul[contains(@id,'PublishDialogDependantList')]", - DEPENDANT_ITEM_VIEWER: "//div[contains(@id,'DependantItemViewer')]", - }, - BUTTONS: { - PUBLISH_REPORT_GENERATE:"//button[contains(@class,'widget-publish-report-button')]", - BUTTON_WITH_SPAN_ADD: "//button[child::span[text()='Add']]", - NEW_CONTENT_BUTTON: "//button[contains(@class,'new-content-button')]", - REFRESH_BUTTON: "//button[contains(@class,'icon-loop')]", - DROP_DOWN_HANDLE: "//button[contains(@id,'DropdownHandle')]", - SELECTION_PANEL_TOGGLER: `//button[contains(@id,'SelectionPanelToggler')]`, - OPTION_SET_MENU_BUTTON: "//button[contains(@id,'MoreButton')]", - SELECTOR_MODE_TOGGLER: "//button[contains(@id,'ModeTogglerButton')]", - UPLOAD_BUTTON: "//button[contains(@class,'upload-button')]", - actionButton: (label) => `//button[contains(@id,'ActionButton') and child::span[contains(.,'${label}')]]`, - button: (label, cssValue) => `//button[contains(@class,'${cssValue}') and child::span[contains(.,'${label}')]]`, - dialogButton: label => `//button[contains(@id,'DialogButton') and child::span[contains(.,'${label}')]]`, - dialogButtonStrict: label => `//button[contains(@id,'DialogButton') and child::span[text()='${label}']]`, - togglerButton: (label) => `//button[contains(@id,'TogglerButton') and child::span[text()='${label}']]`, - MORE_BUTTON: "//button[contains(@id,'MoreButton')]", - }, - TREE_GRID: { - CONTENT_STATUS: "//div[contains(@id,'StatusBlock')]/span", - SORT_DIALOG_TOGGLE: "//div[contains(@class,'sort-dialog-trigger')]", - EXPANDER_ICON_DIV: "//div[contains(@class,'toggle icon-arrow_drop_up')]", - itemByName: name => { - return `//div[contains(@id,'NamesView') and child::p[contains(@class,'xp-admin-common-sub-name') and contains(.,'${name}')]]` - }, - contentStatusByDisplayName: (parent, displayName) => { - return `//div[contains(@id,'ContentSummaryAndCompareStatusViewer') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]` - }, - contentStatusByName: name => { - return `//div[contains(@id,'ContentSummaryAndCompareStatusViewer') and descendant::p[contains(@class,'sub-name') and contains(.,'${name}')]]` - }, - itemTreeGridListElementByDisplayName: displayName => { - return `(//li[contains(@id,'ContentsTreeGridListElement') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]])[last()]` - }, - archiveItemTreeGridListElementByDisplayName: displayName => { - return `(//li[contains(@id,'ArchiveTreeListElement') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]])[last()]` - }, - archiveItemTreeGridListElementByName: name => { - return `(//li[contains(@id,'ArchiveTreeListElement') and descendant::p[contains(@class,'sub-name') and contains(.,'${name}')]])[last()]` - }, - itemTreeGridListElementByName: name => { - return `//li[contains(@id,'ContentsTreeGridListElement') and descendant::p[contains(@class,'sub-name') and contains(.,'${name}')]]` - }, - }, - INPUTS: { - TEXT_INPUT: "//input[@type='text']", - CHECKBOX_INPUT: "//input[@type='checkbox']", - DROPDOWN_OPTION_FILTER_INPUT: "//input[contains(@id,'DropdownOptionFilterInput')]", - }, - DROPDOWN_SELECTOR: { - contentListElementByDisplayName: (container, displayName) => { - return container + - `//li[contains(@id,'ContentListElement') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]`; - }, - // non-clickable li element in options dropdown list, it is for checking read-only status - contentListElementByName: (container, name) => { - return container + - `//li[contains(@id,'ContentListElement') and descendant::p[contains(@class,'sub-name') and contains(.,'${name}')]]`; - }, - // clickable option in dropdown options list - dropdownListItemByDisplayName: (container, displayName) => { - return container + - `//li[contains(@class,'item-view-wrapper')]//h6[contains(@class,'main-name') and contains(.,'${displayName}')]`; - }, - dropdownListItemByName: (container, name) => { - return container + - `//li[contains(@class,'item-view-wrapper')]//p[contains(@class,'sub-name') and contains(.,'${name}')]`; - }, - flatModeDropdownImgItemByDisplayName: (container, displayName) => { - return container + - `//li[contains(@class,'item-view-wrapper') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]//img`; - }, - IMG_DROPDOWN_OPT_DISPLAY_NAME_FLAT_MODE: "//li[contains(@class,'item-view-wrapper')]" + - "//div[contains(@id,'NamesView')]//h6[contains(@class,'main-name')]", - OPTIONS_LI_ELEMENT: "//li[contains(@id,'ContentListElement')]", - DROPDOWN_HANDLE: "//button[contains(@id,'DropdownHandle')]", - OPTION_FILTER_INPUT: "//input[contains(@id,'OptionFilterInput') and contains(@class, 'option-filter-input')]", - MODE_TOGGLER_BUTTON: "//button[contains(@id,'ModeTogglerButton')]", - APPLY_SELECTION_BUTTON: "//button[contains(@class,'apply-selection-button')]", - CONTENT_TREE_SELECTOR: "//div[contains(@id,'ContentTreeSelectorDropdown')]", - CONTENTS_TREE_LIST_UL: "//ul[contains(@id,'ContentsTreeList')]", - DROPDOWN_LIST_ITEM: "//li[contains(@class,'item-view-wrapper')]", - WIDGET_FILTER_DROPDOWN: `//div[contains(@id,'WidgetFilterDropdown')]`, - FILTERABLE_LISTBOX: "//div[contains(@id,'FilterableListBoxWrapper')]", - }, - DIV: { - FRAGMENT_DROPDOWN_DIV: `//div[contains(@id,'FragmentDropdown')]`, - CHECKBOX_DIV: "//div[contains(@id,'Checkbox')]", - DROPDOWN_DIV: "//div[contains(@id,'Dropdown')]", - NOTIFICATION_ACTIONS_DIV: "//div[@class='notification-actions']", - CONTENT_SUMMARY_AND_STATUS_VIEWER: "//div[contains(@id,'ContentSummaryAndCompareStatusViewer')]", - }, }); diff --git a/testing/libs/project.utils.js b/testing/libs/project.utils.js index 9c24e5e1..756582ff 100644 --- a/testing/libs/project.utils.js +++ b/testing/libs/project.utils.js @@ -10,7 +10,7 @@ const ProjectWizardDialogPermissionsStep = require('../page_objects/project/proj const ProjectWizardDialogApplicationsStep = require('../page_objects/project/project-wizard-dialog/project.wizard.applications.step'); const ProjectWizardDialogNameAndIdStep = require('../page_objects/project/project-wizard-dialog/project.wizard.name.id.step'); const ProjectWizardDialogSummaryStep = require('../page_objects/project/project-wizard-dialog/project.wizard.summary.step'); -const appConst = require('./app_const'); +const appConst = require("./app_const"); const path = require('path'); const fs = require('fs'); const webDriverHelper = require('./WebDriverHelper'); @@ -36,16 +36,15 @@ module.exports = { await summaryStep.waitForDialogClosed(); return await settingsBrowsePanel.pause(500); }, - async fillParentNameStep(parents) { + async selectParentProjectsByName(parents) { try { let parentProjectStep = new ProjectWizardDialogParentProjectStep(); parents = [].concat(parents); let selectedItems = await parentProjectStep.getSelectedProjects(); for (let name of parents) { if (selectedItems.length === 0 || this.isProjectSelected(selectedItems, name)) { - // TODO slickgrid - uncomment this string - await parentProjectStep.selectParentProject(name); - //await parentProjectStep.selectParentProjectById(name); + // select a project and click on Apply button + await parentProjectStep.selectParentProjectMulti(name); } } await parentProjectStep.clickOnNextButton(); @@ -55,6 +54,23 @@ module.exports = { throw new Error(`Error occurred in parent project step, screenshot:${screenshot} ` + err); } }, + async selectSingleParentProjectsByName(parent) { + try { + let parentProjectStep = new ProjectWizardDialogParentProjectStep(); + let selectedItems = await parentProjectStep.getSelectedProjects(); + + let isSelected = selectedItems.length > 0 && selectedItems[0].includes(parent); + if (!isSelected) { + await parentProjectStep.selectParentProject(parent); + } + + await parentProjectStep.clickOnNextButton(); + return new ProjectWizardDialogLanguageStep(); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_parent_proj_step'); + throw new Error(`Error occurred in parent project step, screenshot:${screenshot} ` + err); + } + }, isProjectSelected(arr, text) { arr.find((item) => { if (item.includes(text)) { @@ -133,7 +149,13 @@ module.exports = { let parentProjectStep = new ProjectWizardDialogParentProjectStep(); await parentProjectStep.clickOnSkipButton(); } else { - let languageStep = await this.fillParentNameStep(project.parents); + let languageStep; + if (Array.isArray(project.parents)) { + languageStep = await this.selectParentProjectsByName(project.parents); + } else { + languageStep = await this.selectSingleParentProjectsByName(project.parents); + } + await languageStep.waitForLoaded(); } let accessModeStep = await this.fillLanguageStep(project.language); diff --git a/testing/libs/studio.utils.js b/testing/libs/studio.utils.js index 73f19b81..6d02eb6b 100644 --- a/testing/libs/studio.utils.js +++ b/testing/libs/studio.utils.js @@ -17,11 +17,10 @@ const DeleteContentDialog = require('../page_objects/delete.content.dialog'); const ContentPublishDialog = require('../page_objects/content.publish.dialog'); const BrowseDetailsPanel = require('../page_objects/browsepanel/detailspanel/browse.details.panel'); const BrowseDependenciesWidget = require('../page_objects/browsepanel/detailspanel/browse.dependencies.widget'); -const BrowseLayersWidget = require('../page_objects/browsepanel/detailspanel/browse.layers.widget'); const ContentUnpublishDialog = require('../page_objects/content.unpublish.dialog'); const CreateRequestPublishDialog = require('../page_objects/issue/create.request.publish.dialog'); const ProjectSelectionDialog = require('../page_objects/project/project.selection.dialog'); -const ArchiveBrowsePanel = require('../page_objects/archive/archive.browse.panel'); +const SettingsBrowsePanel = require('../page_objects/project/settings.browse.panel'); const UserBrowsePanel = require('../page_objects/users/userbrowse.panel'); const UserWizard = require('../page_objects/users/user.wizard'); const NewPrincipalDialog = require('../page_objects/users/new.principal.dialog'); @@ -32,12 +31,13 @@ const ConfirmValueDialog = require('../page_objects/confirm.content.delete.dialo const DateTimeRange = require('../page_objects/components/datetime.range'); const WizardDependenciesWidget = require('../page_objects/wizardpanel/details/wizard.dependencies.widget'); const WizardDetailsPanel = require('../page_objects/wizardpanel/details/wizard.details.panel'); -const BrowseVariantsWidget = require('../page_objects/browsepanel/detailspanel/browse.variants.widget'); -const SettingsBrowsePanel = require('../page_objects/project/settings.browse.panel'); const fs = require('fs'); const path = require('path'); const PropertiesWidgetItem = require('../page_objects/browsepanel/detailspanel/properties.widget.itemview'); +const ArchiveBrowsePanel = require('../page_objects/archive/archive.browse.panel'); const EditSettingDialog = require('../page_objects/details_panel/edit.settings.dialog'); +const BrowseLayersWidget = require('../page_objects/browsepanel/detailspanel/browse.layers.widget'); +const BrowseVariantsWidget = require('../page_objects/browsepanel/detailspanel/browse.variants.widget'); module.exports = { @@ -108,6 +108,7 @@ module.exports = { scrollViewPort(viewportElement, step) { return this.getBrowser().execute("arguments[0].scrollTop=arguments[1]", viewportElement, step); }, + async doCloseCurrentBrowserTab() { let title = await this.getBrowser().getTitle(); if (title != 'Enonic XP Home') { @@ -121,6 +122,19 @@ module.exports = { await issueListDialog.waitForDialogOpened(); return await issueListDialog.pause(300); }, + async openCreateIssueDialog() { + try { + let browsePanel = new BrowsePanel(); + let createIssueDialog = new CreateIssueDialog(); + let issueListDialog = new IssueListDialog(); + await browsePanel.clickOnShowIssuesListButton(); + await issueListDialog.waitForDialogOpened(); + await issueListDialog.clickOnNewIssueButton(); + return await createIssueDialog.waitForDialogLoaded(); + } catch (err) { + throw new Error("Error when opening 'Create Issue Dialog' " + err); + } + }, async createPublishRequest(text) { try { let browsePanel = new BrowsePanel(); @@ -212,6 +226,7 @@ module.exports = { let contentWizardPanel = new ContentWizardPanel(); let browsePanel = new BrowsePanel(); await this.findAndSelectItem(contentName); + await browsePanel.waitForSpinnerNotVisible(appConst.mediumTimeout); await browsePanel.clickOnLocalizeButton(); await this.doSwitchToNewWizard(); await contentWizardPanel.waitForOpened(); @@ -227,6 +242,18 @@ module.exports = { await contentWizardPanel.waitAndClickOnSave(); return await this.doCloseWizardAndSwitchToGrid(); }, + async doAddPublishedShortcut(shortcut) { + let contentWizardPanel = new ContentWizardPanel(); + //Open new shortcut-wizard: + await this.openContentWizard(appConst.contentTypes.SHORTCUT); + await contentWizardPanel.typeData(shortcut); + await contentWizardPanel.clickOnMarkAsReadyButton(); + let contentPublishDialog = new ContentPublishDialog(); + await contentPublishDialog.clickOnPublishNowButton(); + await contentPublishDialog.waitForDialogClosed(); + await contentWizardPanel.waitForNotificationMessage(); + return await this.doCloseWizardAndSwitchToGrid(); + }, async doAddReadyFolder(folder) { let contentWizardPanel = new ContentWizardPanel(); await this.openContentWizard(appConst.contentTypes.FOLDER); @@ -235,6 +262,18 @@ module.exports = { await this.doCloseWizardAndSwitchToGrid(); return await this.getBrowser().pause(1000); }, + async doAddPublishedFolder(folder) { + let contentWizardPanel = new ContentWizardPanel(); + await this.openContentWizard(appConst.contentTypes.FOLDER); + await contentWizardPanel.typeData(folder); + await contentWizardPanel.clickOnMarkAsReadyButton(); + let contentPublishDialog = new ContentPublishDialog(); + await contentPublishDialog.clickOnPublishNowButton(); + await contentPublishDialog.waitForDialogClosed(); + await contentWizardPanel.waitForNotificationMessage(); + await this.doCloseWizardAndSwitchToGrid(); + return await this.getBrowser().pause(1000); + }, async doAddFolder(folder) { let contentWizardPanel = new ContentWizardPanel(); // 1. Open the folder-wizard: @@ -250,6 +289,12 @@ module.exports = { await this.doCloseCurrentBrowserTab(); return await this.doSwitchToContentBrowsePanel(); }, + async doCloseWizardAndSwitchContentStudioTab() { + await this.doCloseCurrentBrowserTab(); + let browsePanel = new BrowsePanel(); + await this.getBrowser().switchWindow(appConst.BROWSER_TITLES.CONTENT_STUDIO); + await browsePanel.pause(400); + }, async doAddSite(site, noControllers) { let contentWizardPanel = new ContentWizardPanel(); //1. Open new site-wizard: @@ -377,20 +422,37 @@ module.exports = { return await this.getBrowser().pause(1000); }, async findAndSelectItem(name) { - let browsePanel = new BrowsePanel(); - await this.typeNameInFilterPanel(name); - await browsePanel.waitForRowByNameVisible(name); - await browsePanel.pause(400); - await browsePanel.clickOnRowByName(name); - return await browsePanel.pause(400); + try { + let browsePanel = new BrowsePanel(); + await this.typeNameInFilterPanel(name); + await browsePanel.waitForRowByNameVisible(name); + await browsePanel.pause(200); + await browsePanel.clickOnRowByName(name); + await browsePanel.waitForSpinnerNotVisible(appConst.longTimeout); + return await browsePanel.pause(300); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_select_item'); + throw new Error("Select a item, error screenshot:" + screenshot + ' ' + err); + } + }, + async saveScreenshotUniqueName(namePart) { + let screenshotName = appConst.generateRandomName(namePart); + await this.saveScreenshot(screenshotName); + return screenshotName; }, async findAndSelectItemByDisplayName(displayName) { - let browsePanel = new BrowsePanel(); - await this.typeNameInFilterPanel(displayName); - await browsePanel.waitForContentByDisplayNameVisible(displayName); - await browsePanel.pause(300); - await browsePanel.clickOnRowByDisplayName(displayName); - return await browsePanel.pause(400); + try { + let browsePanel = new BrowsePanel(); + await this.typeNameInFilterPanel(displayName); + await browsePanel.waitForContentByDisplayNameVisible(displayName); + await browsePanel.pause(200); + await browsePanel.clickOnRowByDisplayName(displayName); + await browsePanel.waitForSpinnerNotVisible(appConst.longTimeout); + return await browsePanel.pause(300); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_select_item'); + throw new Error("Select a item, error screenshot:" + screenshot + ' ' + err); + } }, // find the content, select it and click 'Delete' menu item in the modal dialog @@ -429,7 +491,8 @@ module.exports = { await this.switchToContentTabWindow(displayName); await contentWizardPanel.waitForOpened(); await contentWizardPanel.waitForSpinnerNotVisible(appConst.longTimeout); - return await contentWizardPanel.waitForDisplayNameInputFocused(); + await contentWizardPanel.waitForDisplayNameInputFocused(); + await contentWizardPanel.pause(300); }, async findContentAndClickCheckBox(displayName) { let browsePanel = new BrowsePanel(); @@ -449,6 +512,7 @@ module.exports = { async clickOnItemInNewContentDialog(contentType) { let newContentDialog = new NewContentDialog(); let contentWizard = new ContentWizardPanel(); + await newContentDialog.waitForOpened(); await newContentDialog.typeSearchText(contentType); await newContentDialog.clickOnContentType(contentType); await this.doSwitchToNewWizard(); @@ -485,7 +549,7 @@ module.exports = { } await filterPanel.typeSearchText(name); await browsePanel.waitForSpinnerNotVisible(appConst.longTimeout); - return await browsePanel.pause(500); + return await browsePanel.pause(800); } catch (err) { await this.saveScreenshot(appConst.generateRandomName('err_spinner')); throw new Error('Filter Panel- error : ' + err); @@ -502,22 +566,13 @@ module.exports = { throw new Error('Error when opening Filter Panel! ' + err); } }, - async clickOnClearSelection() { - try { - let filterPanel = new FilterPanel(); - return await filterPanel.clickOnClearLink(); - } catch (err) { - throw new Error('Error when clicking on Clear in Filter Panel! ' + err); - } - }, async openProjectSelectionDialogAndSelectContext(context) { try { let browsePanel = new BrowsePanel(); return await browsePanel.selectContext(context); } catch (err) { - let screenshot = appConst.generateRandomName('err_select_context'); - await this.saveScreenshot(screenshot); + let screenshot = await this.saveScreenshotUniqueName('err_select_context'); throw new Error('Error during selecting a context, screenshot: ' + screenshot + " " + err); } }, @@ -534,11 +589,10 @@ module.exports = { async navigateToContentStudioApp(userName, password) { try { await this.clickOnContentStudioLink(userName, password); - return await this.doSwitchToContentBrowsePanel(); + await this.doSwitchToContentBrowsePanelAndSelectDefaultContext(); } catch (err) { - let screenshot = appConst.generateRandomName('err_navigate_cs'); - this.saveScreenshot(screenshot); - throw new Error('error when navigate to Content Studio app. Screenshot: ' + screenshot + ' ' + err); + let screenshot = await this.saveScreenshotUniqueName('err_navigate_cs'); + throw new Error(`Error occurred after clicking on Content Studio link in Launcher Panel, screenshot:${screenshot} ` + err); } }, async navigateToContentStudioAppMobile(userName, password) { @@ -554,23 +608,13 @@ module.exports = { await this.getBrowser().switchWindow("Content Studio - Enonic XP Admin"); return await browsePanel.pause(1500); } catch (err) { - console.log('tried to navigate to Content Studio app, but: ' + err); - this.saveScreenshot(appConst.generateRandomName('err_navigate_to_studio')); - throw new Error('error when navigate to Content Studio app ' + err); + let screenshot = await this.saveScreenshotUniqueName('err_navigate_to_studio'); + throw new Error('error when navigate to Content Studio, screenshot: ' + screenshot + ' ' + err); } }, - async openVariantsWidget() { - let browsePanel = new BrowsePanel(); - let browseDetailsPanel = new BrowseDetailsPanel(); - let browseVariantsWidget = new BrowseVariantsWidget(); - await browsePanel.openDetailsPanel(); - await browseDetailsPanel.openVariants(); - await browseVariantsWidget.waitForWidgetLoaded(); - return browseVariantsWidget; - }, async clickOnContentStudioLink(userName, password) { let launcherPanel = new LauncherPanel(); - let result = await launcherPanel.isDisplayed(appConst.shortTimeout); + let result = await launcherPanel.isDisplayed(2000); console.log('Launcher Panel is opened, click on the `Content Studio` link...'); if (result) { await launcherPanel.clickOnContentStudioLink(); @@ -585,8 +629,7 @@ module.exports = { await this.getBrowser().switchWindow('Content Studio - Enonic XP Admin'); await this.closeProjectSelectionDialog(); } catch (err) { - let screenshot = appConst.generateRandomName('err_navigate_to_studio') - await this.saveScreenshot(screenshot); + let screenshot = await this.saveScreenshotUniqueName('err_navigate_to_studio'); throw new Error('Error when navigate to Content Studio app. Screenshot: ' + screenshot + " " + err); } }, @@ -608,24 +651,29 @@ module.exports = { return await launcherPanel.clickOnContentStudioLink(); }, - async openArchivePanel() { + async doSwitchToContentBrowsePanel() { try { - let archiveBrowsePanel = new ArchiveBrowsePanel(); - await this.openContentStudioMenu(); - await this.waitForElementDisplayed(lib.ARCHIVE_BUTTON, appConst.mediumTimeout); - await this.clickOnElement(lib.ARCHIVE_BUTTON); - await this.getBrowser().pause(300); - await archiveBrowsePanel.waitForGridLoaded(appConst.mediumTimeout); + let browsePanel = new BrowsePanel(); + await this.getBrowser().switchWindow(appConst.BROWSER_TITLES.CONTENT_STUDIO); + console.log('switched to content browse panel...'); + await browsePanel.waitForGridLoaded(appConst.longTimeout); + return browsePanel; } catch (err) { - await this.saveScreenshot(appConst.generateRandomName("err_open_settings")); - throw new Error("Error Open Archive Panel: " + err); + throw new Error('Error when switching to Content Studio App ' + err); } }, - async doSwitchToContentBrowsePanel() { + async doSwitchToContentBrowsePanelAndSelectDefaultContext() { try { + let projectSelectionDialog = new ProjectSelectionDialog(); let browsePanel = new BrowsePanel(); - await this.getBrowser().switchWindow('Content Studio - Enonic XP Admin'); + await this.getBrowser().switchWindow(appConst.BROWSER_TITLES.CONTENT_STUDIO); console.log('switched to content browse panel...'); + let isLoaded = await projectSelectionDialog.isDialogLoaded(); + if (isLoaded) { + await projectSelectionDialog.selectContext('Default'); + await projectSelectionDialog.waitForDialogClosed(); + return await this.getBrowser().pause(200); + } await browsePanel.waitForGridLoaded(appConst.longTimeout); return browsePanel; } catch (err) { @@ -635,7 +683,7 @@ module.exports = { async doSwitchToHome() { console.log('testUtils:switching to Home page...'); let homePage = new HomePage(); - await this.getBrowser().switchWindow('Enonic XP Home'); + await this.getBrowser().switchWindow(appConst.BROWSER_TITLES.XP_HOME); return await homePage.waitForLoaded(appConst.mediumTimeout); }, @@ -679,7 +727,11 @@ module.exports = { let contentWizardPanel = new ContentWizardPanel(); let tabs = await this.getBrowser().getWindowHandles(); await this.getBrowser().switchToWindow(tabs[tabs.length - 1]); - return contentWizardPanel.waitForOpened(); + return await contentWizardPanel.waitForOpened(); + }, + async doSwitchToTabByIndex(index) { + let tabs = await this.getBrowser().getWindowHandles(); + await this.getBrowser().switchToWindow(tabs[index]); }, async doSwitchToNextTab() { let tabs = await this.getBrowser().getWindowHandles(); @@ -689,7 +741,17 @@ module.exports = { let tabs = await this.getBrowser().getWindowHandles(); return await this.getBrowser().switchToWindow(tabs[tabs.length - 2]); }, - doCloseAllWindowTabsAndSwitchToHome: function () { + async doCloseWindowTabByTitle(title) { + let arrayId = await this.getBrowser().getWindowHandles(); + for (const item of arrayId) { + let result = await this.switchAndCheckTitle(item, title); + if (result) { + await this.getBrowser().closeWindow(); + } + } + await this.doSwitchToHome(); + }, + doCloseAllWindowTabsAndSwitchToHome() { return this.getBrowser().getWindowHandles().then(tabIds => { let result = Promise.resolve(); tabIds.forEach(tabId => { @@ -710,7 +772,7 @@ module.exports = { return this.doSwitchToHome(); }); }, - switchAndCheckTitle: function (handle, reqTitle) { + switchAndCheckTitle(handle, reqTitle) { return this.getBrowser().switchToWindow(handle).then(() => { return this.getBrowser().getTitle().then(title => { return title.includes(reqTitle); @@ -720,7 +782,6 @@ module.exports = { }) }); }, - async saveScreenshot(name, that) { try { let screenshotsDir = path.join(__dirname, '/../build/reports/screenshots/'); @@ -741,15 +802,6 @@ module.exports = { await browseDetailsPanel.openDependencies(); return await browseDependenciesWidget.waitForWidgetLoaded(); }, - async openLayersWidgetInBrowsePanel() { - let browsePanel = new BrowsePanel(); - let browseDetailsPanel = new BrowseDetailsPanel(); - let browseLayersWidget = new BrowseLayersWidget(); - await browsePanel.openDetailsPanel(); - await browseDetailsPanel.openLayers(); - await browseLayersWidget.waitForWidgetLoaded(); - return browseLayersWidget; - }, isStringEmpty(str) { return (!str || 0 === str.length); }, @@ -891,7 +943,7 @@ module.exports = { //await wizardPanel.waitForNotificationMessage(); await wizardPanel.pause(2000); //Click on Close icon and close the wizard: - return await browsePanel.doClickOnCloseTabAndWaitGrid(displayName); + return await browsePanel.closeTabAndWaitForGrid(displayName); }, async clickOnSystemOpenUserWizard() { let browsePanel = new UserBrowsePanel(); @@ -917,7 +969,6 @@ module.exports = { let launcherPanel = new LauncherPanel(); let selector = "//button[contains(@class,'launcher-button')]"; try { - // await this.waitUntilDisplayed(selector, 2000); await this.getBrowser().pause(100); await this.clickOnElement(selector); //let el = await this.getDisplayedElements(selector); @@ -937,7 +988,10 @@ module.exports = { }, async getDisplayedElements(selector) { - let elements = this.getBrowser().$$(selector); + let elements = await this.getBrowser().$$(selector); + if (elements.length === 0) { + return []; + } let pr = elements.map(el => el.isDisplayed()); return await Promise.all(pr).then(result => { return elements.filter((el, i) => result[i]); @@ -952,11 +1006,11 @@ module.exports = { }, async scheduleContent(contentName, date) { let contentBrowsePanel = new ContentBrowsePanel(); - let dateTimeRange = new DateTimeRange(); + let dateTimeRange = new DateTimeRange("//div[contains(@id,'ContentPublishDialog')]"); await contentBrowsePanel.openPublishMenuSelectItem(appConst.PUBLISH_MENU.PUBLISH); let contentPublishDialog = new ContentPublishDialog(); await contentPublishDialog.clickOnAddScheduleIcon(); - await dateTimeRange.typeOnlineFrom(date, "//div[contains(@id,'ContentPublishDialog')]"); + await dateTimeRange.typeOnlineFrom(date); await contentPublishDialog.clickOnScheduleButton(); return await contentPublishDialog.waitForDialogClosed(); }, @@ -993,15 +1047,7 @@ module.exports = { loadUrl(url) { return this.getBrowser().url(url); }, - async getIdOfHtmlAreas() { - let selector = lib.FORM_VIEW + lib.TEXT_AREA; - let elems = await this.getBrowser().$$(selector); - let ids = []; - for (const item of elems) { - ids.push(await item.getAttribute('id')); - } - return ids; - }, + async openEditSettingDialog() { let propertiesWidgetItem = new PropertiesWidgetItem(); let editSettingsDialog = new EditSettingDialog(); @@ -1010,4 +1056,35 @@ module.exports = { await editSettingsDialog.waitForLoaded(); return editSettingsDialog; }, + async openArchivePanel() { + try { + let archiveBrowsePanel = new ArchiveBrowsePanel(); + await this.openContentStudioMenu(); + await this.waitForElementDisplayed(lib.BUTTONS.ARCHIVE_BUTTON, appConst.mediumTimeout); + await this.clickOnElement(lib.BUTTONS.ARCHIVE_BUTTON); + await this.getBrowser().pause(300); + await archiveBrowsePanel.waitForGridLoaded(appConst.mediumTimeout); + } catch (err) { + await this.saveScreenshot(appConst.generateRandomName("err_open_settings")); + throw new Error("Error Open Archive Panel: " + err); + } + }, + async openLayersWidgetInBrowsePanel() { + let browsePanel = new BrowsePanel(); + let browseDetailsPanel = new BrowseDetailsPanel(); + let browseLayersWidget = new BrowseLayersWidget(); + await browsePanel.openDetailsPanel(); + await browseDetailsPanel.openLayers(); + await browseLayersWidget.waitForWidgetLoaded(); + return browseLayersWidget; + }, + async openVariantsWidget() { + let browsePanel = new BrowsePanel(); + let browseDetailsPanel = new BrowseDetailsPanel(); + let browseVariantsWidget = new BrowseVariantsWidget(); + await browsePanel.openDetailsPanel(); + await browseDetailsPanel.openVariants(); + await browseVariantsWidget.waitForWidgetLoaded(); + return browseVariantsWidget; + }, }; diff --git a/testing/page_objects/archive/archive.browse.panel.js b/testing/page_objects/archive/archive.browse.panel.js index 4c6559ad..8a82c58f 100644 --- a/testing/page_objects/archive/archive.browse.panel.js +++ b/testing/page_objects/archive/archive.browse.panel.js @@ -33,9 +33,13 @@ const XPATH = { class ArchiveBrowsePanel extends BaseBrowsePanel { + get browseToolbar() { + return XPATH.toolbar; + } get container() { return XPATH.container; } + get deleteButton() { return XPATH.toolbar + `/*[contains(@id, 'ActionButton') and child::span[text()='Delete...']]`; } @@ -194,7 +198,7 @@ class ArchiveBrowsePanel extends BaseBrowsePanel { return await this.pause(200); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_find_item'); - throw new Error(`Row with the displayName ${displayName} was not found. Screenshot:` + screenshot + ' ' + err); + throw new Error(`Row with the displayName ${displayName} was not found. Screenshot:${screenshot} ` + err); } } @@ -219,7 +223,7 @@ class ArchiveBrowsePanel extends BaseBrowsePanel { await this.pause(200); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_select_item'); - throw Error('Row with the name was not selected, screenshot: ' + screenshot + ' ' + err) + throw Error(`Row with the name was not selected, screenshot:${screenshot} ` + err) } } diff --git a/testing/page_objects/archive/archive.delete.dialog.js b/testing/page_objects/archive/archive.delete.dialog.js index 833a1fb8..58a5b8a8 100644 --- a/testing/page_objects/archive/archive.delete.dialog.js +++ b/testing/page_objects/archive/archive.delete.dialog.js @@ -23,7 +23,7 @@ class ArchiveDeleteDialog extends Page { } get cancelButton() { - return XPATH.container + lib.CANCEL_BUTTON_DIALOG; + return XPATH.container + lib.dialogButton('Cancel'); } get cancelButtonTop() { diff --git a/testing/page_objects/archive/archive.filter.panel.js b/testing/page_objects/archive/archive.filter.panel.js index 6533b5b6..31036cee 100644 --- a/testing/page_objects/archive/archive.filter.panel.js +++ b/testing/page_objects/archive/archive.filter.panel.js @@ -160,8 +160,8 @@ class ArchiveFilterPanel extends Page { await this.clickOnElement(selector); return await this.pause(1200); } catch (err) { - let screenshot = await this.saveScreenshotUniqueName(filter_panel); - throw new Error('Filter Panel ,error after clicking on a checkbox in aggregation block, screenshot: ' + screenshot + ' ' + err); + let screenshot = await this.saveScreenshotUniqueName('filter_panel'); + throw new Error(`Filter Panel ,error after clicking on a checkbox in aggregation block, screenshot: ${screenshot} ` + err); } } @@ -220,8 +220,8 @@ class ArchiveFilterPanel extends Page { await this.clickOnElement(selector); return await this.pause(1200); } catch (err) { - let screenshot = await this.saveScreenshotUniqueName("err_click_on_aggregation"); - throw new Error("Error when click on the aggregation checkbox, screenshot: " + screenshot + ' ' + err); + let screenshot = await this.saveScreenshotUniqueName('err_click_on_aggregation'); + throw new Error(`Error when click on the aggregation checkbox, screenshot:${screenshot} ` + err); } } @@ -240,7 +240,7 @@ class ArchiveFilterPanel extends Page { let endIndex = label.indexOf(')'); return label.substring(startIndex + 1, endIndex); } catch (err) { - await this.saveScreenshot(appConst.generateRandomName('err_numb_in_aggregation')); + await this.saveScreenshotUniqueName('err_numb_in_aggregation'); throw new Error("Error when get the number in aggregation checkbox: " + err); } } @@ -294,7 +294,7 @@ class ArchiveFilterPanel extends Page { await this.pause(300); } catch (err) { let screenshot = await this.saveScreenshot('err_filter_owner'); - throw new Error("Error when selecting an option in Owner Selector, screenshot " + screenshot + ' ' + err); + throw new Error(`Error when selecting an option in Owner Selector, screenshot ; ${screenshot} ` + err); } } diff --git a/testing/page_objects/archive/archive.restore.dialog.js b/testing/page_objects/archive/archive.restore.dialog.js index 8d29b878..a134f6d2 100644 --- a/testing/page_objects/archive/archive.restore.dialog.js +++ b/testing/page_objects/archive/archive.restore.dialog.js @@ -47,7 +47,7 @@ class ArchiveRestoreDialog extends Page { await this.waitForElementDisplayed(this.restoreButton, appConst.mediumTimeout) } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_restore_dlg'); - throw new Error('Restore from Archive dialog was not loaded! screenshot: ' + screenshot + ' ' + err); + throw new Error(`Restore from Archive dialog was not loaded! screenshot:${screenshot} ` + err); } } @@ -56,7 +56,7 @@ class ArchiveRestoreDialog extends Page { await this.waitForElementNotDisplayed(XPATH.container, appConst.longTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_restore_dlg_close'); - throw new Error('Restore from Archive dialog was not closed, screenshot: ' + screenshot + ' ' + err); + throw new Error(`Restore from Archive dialog was not closed, screenshot: ${screenshot}` + err); } } diff --git a/testing/page_objects/archive/archive.widget.item.view.js b/testing/page_objects/archive/archive.widget.item.view.js index 2f7b7bfb..3141a595 100644 --- a/testing/page_objects/archive/archive.widget.item.view.js +++ b/testing/page_objects/archive/archive.widget.item.view.js @@ -33,7 +33,7 @@ class ArchiveContentWidgetItemView extends Page { try { return await this.waitForElementNotDisplayed(xpath.container, appConst.shortTimeout); } catch (err) { - await this.saveScreenshot("err_widget_item_is_visible"); + await this.saveScreenshot('err_widget_item_is_visible'); throw new Error("Widget Item should not be displayed " + err); } } @@ -42,8 +42,8 @@ class ArchiveContentWidgetItemView extends Page { try { return await this.waitForElementNotDisplayed(xpath.workInProgressIcon, appConst.mediumTimeout); } catch (err) { - let screenshot = await this.saveScreenshotUniqueName("err_widget_item_workflow"); - throw new Error("Workflow state should not be displayed in the archive widget item, screenshot " + screenshot + ' ' + err); + let screenshot = await this.saveScreenshotUniqueName('err_widget_item_workflow'); + throw new Error(`Workflow state should not be displayed in the archive widget item, screenshot ${screenshot} ` + err); } } } diff --git a/testing/page_objects/base.browse.panel.js b/testing/page_objects/base.browse.panel.js index a8a126cc..da141876 100644 --- a/testing/page_objects/base.browse.panel.js +++ b/testing/page_objects/base.browse.panel.js @@ -29,7 +29,7 @@ class BaseBrowsePanel extends Page { async waitForGridLoaded(ms) { try { let timeout = typeof ms !== 'undefined' ? ms : appConst.mediumTimeout; - await this.waitForElementDisplayed(this.treeGrid, timeout); + await this.waitForElementDisplayed(this.browseToolbar, timeout); await this.waitForSpinnerNotVisible(timeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_switch'); @@ -115,11 +115,13 @@ class BaseBrowsePanel extends Page { } // gets list of content display names - getDisplayNamesInGrid() { - return this.getTextInElements(this.displayNames).catch(err => { - this.saveScreenshot('err_get_display_name_grid'); - throw new Error(`Error when getting display names in grid` + err); - }); + async getDisplayNamesInGrid() { + try { + return await this.getTextInElements(this.displayNames) + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_get_display_name_grid'); + throw new Error(`Error occurred when getting display names in grid, screenshot:${screenshot} ` + err); + } } async waitForNewButtonDisabled() { @@ -127,7 +129,7 @@ class BaseBrowsePanel extends Page { return await this.waitForElementDisabled(this.newButton, appConst.mediumTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_new_disabled_button'); - throw Error('New... button should be disabled, timeout: ' + screenshot + ' ' + err); + throw Error(`New... button should be disabled, screenshot:${screenshot} ` + err); } } @@ -145,7 +147,7 @@ class BaseBrowsePanel extends Page { await this.pause(400); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_new_button'); - throw new Error('New button is not enabled , screenshot: ' + screenshot + ' ' + err); + throw new Error(`New button is not enabled , screenshot:${screenshot} ` + err); } } @@ -203,7 +205,7 @@ class BaseBrowsePanel extends Page { async clickOnCheckboxByName(name) { let listElements = lib.TREE_GRID.itemTreeGridListElementByName(name); let result = await this.findElements(listElements); - if (result === 0) { + if (result.length === 0) { throw new Error('Checkbox was not found!'); } let listElement = result[result.length - 1]; @@ -298,6 +300,39 @@ class BaseBrowsePanel extends Page { } } + // check for Accessibility attributes: toolbar role + async waitForBrowseToolbarRoleAttribute(expectedRole) { + let locator = this.toolbar; + await this.waitForAttributeValue(locator, appConst.ACCESSIBILITY_ATTRIBUTES.ROLE, expectedRole); + } + + // check for Accessibility attributes: aria-label + async waitForBrowseToolbarAriaLabelAttribute() { + let locator = this.toolbar; + await this.waitForAttributeIsPresent(locator, appConst.ACCESSIBILITY_ATTRIBUTES.ARIA_LABEL); + } + + // check for Accessibility attributes: ContentAppBar role + async waitForContentAppBarRoleAttribute(expectedRole) { + let locator = lib.DIV.CONTENT_APP_BAR_DIV; + await this.waitForAttributeValue(locator, appConst.ACCESSIBILITY_ATTRIBUTES.ROLE, expectedRole); + } + + // check for Accessibility attributes: ContentAppBar aria-label: + async waitForContentAppBarAriaLabelAttribute() { + let locator = lib.DIV.CONTENT_APP_BAR_DIV; + await this.waitForAttributeIsPresent(locator, appConst.ACCESSIBILITY_ATTRIBUTES.ARIA_LABEL); + } + + async waitForProjectViewerRoleAttribute(expectedValue) { + let locator = lib.DIV.CONTENT_APP_BAR_DIV + lib.DIV.PROJECT_VIEWER_DIV; + await this.waitForAttributeValue(locator, appConst.ACCESSIBILITY_ATTRIBUTES.ROLE, expectedValue); + } + + async waitForProjectViewerAriaHasPopupAttribute(expectedValue) { + let locator = lib.DIV.CONTENT_APP_BAR_DIV + lib.DIV.PROJECT_VIEWER_DIV; + await this.waitForAttributeValue(locator, appConst.ACCESSIBILITY_ATTRIBUTES.ARIA_HAS_POPUP, expectedValue); + } } module.exports = BaseBrowsePanel; diff --git a/testing/page_objects/browsepanel/content.browse.panel.js b/testing/page_objects/browsepanel/content.browse.panel.js index 05df538b..368e1770 100644 --- a/testing/page_objects/browsepanel/content.browse.panel.js +++ b/testing/page_objects/browsepanel/content.browse.panel.js @@ -14,13 +14,14 @@ const ContentUnpublishDialog = require('../content.unpublish.dialog'); const XPATH = { container: "//div[contains(@id,'ContentBrowsePanel')]", - toolbar: "//div[contains(@id,'ContentBrowseToolbar')]", + toolbarDiv: "//div[contains(@id,'ContentBrowseToolbar')]", treeGridToolbar: "//div[contains(@id,'ListBoxToolbar') and contains(@class,'tree-grid-toolbar')]", + selectableListBoxPanelDiv: "//div[contains(@id,'SelectableListBoxPanel')]", contentsTreeGridRootUL: "//ul[contains(@id,'ContentsTreeGridRootList')]", appBar: "//div[contains(@id,'AppBar')]", projectViewerButton: "//div[contains(@id,'ProjectViewer')]", - highlightedRow: `//li[contains(@class,'checkbox-left selected') and not(contains(@class,'checked')) ]`, - checkedRowLi: `//li[contains(@class,'checkbox-left selected checked')]`, + highlightedRow: `//div[contains(@class,'checkbox-left selected') and not(contains(@class,'checked')) ]`, + checkedRowLi: `//div[contains(@class,'checkbox-left selected checked')]`, searchButton: "//button[contains(@class, 'icon-search')]", hideSearchPanelButton: "//span[contains(@class, 'hide-filter-panel-button')]", showIssuesListButton: "//button[contains(@id,'ShowIssuesDialogButton')]", @@ -28,72 +29,64 @@ const XPATH = { markAsReadyMenuItem: "//ul[contains(@id,'Menu')]//li[contains(@id,'MenuItem') and text()='Mark as ready']", requestPublishMenuItem: "//ul[contains(@id,'Menu')]//li[contains(@id,'MenuItem') and text()='Request Publish']", contentPublishMenuButton: `//div[contains(@id,'ContentBrowsePublishMenuButton')]`, + selectionControllerCheckBox: `//div[contains(@id,'ListSelectionController')]`, + contentActionMenuButton: `//div[contains(@id,'ContentActionMenuButton')]`, selectionControllerCheckBox: `//div[contains(@id,'SelectionController')]`, numberInSelectionToggler: `//button[contains(@id,'SelectionPanelToggler')]/span`, - contentSummaryListViewerByName(name) { return `//div[contains(@id,'ContentSummaryListViewer') and descendant::p[contains(@class,'sub-name') and contains(.,'${name}')]]` }, - contentSummaryByName(name) { - return `//div[contains(@id,'ContentSummaryListViewer') and descendant::p[contains(@class,'sub-name') and contains(.,'${name}')]]` - }, - contentSummaryByDisplayName(displayName) { - return `//div[contains(@id,'ContentSummaryListViewer') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]` - }, publishMenuItemByName(name) { return `//ul[contains(@id,'Menu')]//li[contains(@id,'MenuItem') and contains(.,'${name}')]` }, - rowByDisplayName: - displayName => `//div[contains(@id,'NamesView') and child::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]`, - defaultActionByName: name => `//button[contains(@id, 'ActionButton') and child::span[contains(.,'${name}')]]`, foldButtonByName: name => `//div[contains(@id,'ContentBrowseToolbar')]//span[text()='${name}']`, }; class ContentBrowsePanel extends BaseBrowsePanel { - get container() { - return XPATH.container; - } - get treeGridToolbar() { return XPATH.treeGridToolbar; } + get toolbar() { + return XPATH.toolbarDiv; + } + get archiveButton() { - return XPATH.toolbar + lib.actionButton('Archive...'); + return XPATH.toolbarDiv + lib.actionButton('Archive...'); } get moreButton() { - return XPATH.toolbar + lib.BUTTONS.MORE_BUTTON; + return XPATH.toolbarDiv + lib.BUTTONS.MORE_BUTTON; } get moveButton() { - return XPATH.toolbar + lib.actionButton('Move...'); + return XPATH.toolbarDiv + lib.actionButton('Move...'); } get duplicateButton() { - return XPATH.toolbar + lib.actionButton('Duplicate...'); + return XPATH.toolbarDiv + lib.actionButton('Duplicate...'); } get previewButton() { - return XPATH.toolbar + lib.actionButton('Preview'); + return XPATH.toolbarDiv + lib.actionButton('Preview'); } get sortButton() { - return XPATH.toolbar + lib.actionButton('Sort...'); + return XPATH.toolbarDiv + lib.actionButton('Sort...'); } get localizeButton() { - return XPATH.toolbar + lib.actionButton('Localize'); + return XPATH.toolbarDiv + lib.actionButton('Localize'); } get openButton() { - return XPATH.toolbar + lib.actionButton('Open'); + return XPATH.toolbarDiv + lib.actionButton('Open'); } get searchButton() { - return XPATH.toolbar + XPATH.searchButton; + return XPATH.toolbarDiv + XPATH.searchButton; } get hideSearchPanelButton() { @@ -105,23 +98,23 @@ class ContentBrowsePanel extends BaseBrowsePanel { } get showPublishMenuButton() { - return XPATH.toolbar + XPATH.contentPublishMenuButton + lib.DROP_DOWN_HANDLE; + return XPATH.toolbarDiv + XPATH.contentActionMenuButton + lib.DROP_DOWN_HANDLE; } get createIssueMenuItem() { - return XPATH.toolbar + XPATH.createIssueMenuItem; + return XPATH.toolbarDiv + XPATH.createIssueMenuItem; } get requestPublishMenuItem() { - return XPATH.toolbar + XPATH.requestPublishMenuItem; + return XPATH.toolbarDiv + XPATH.requestPublishMenuItem; } get markAsReadyMenuItem() { - return XPATH.toolbar + XPATH.markAsReadyMenuItem; + return XPATH.toolbarDiv + XPATH.markAsReadyMenuItem; } get createIssueButton() { - return XPATH.toolbar + lib.actionButton('Create Issue...'); + return XPATH.toolbarDiv + lib.actionButton('Create Issue...'); } get showIssuesListButton() { @@ -137,11 +130,11 @@ class ContentBrowsePanel extends BaseBrowsePanel { } get newButton() { - return `${XPATH.toolbar}/*[contains(@id, 'ActionButton') and child::span[contains(.,'New...')]]` + return `${XPATH.toolbarDiv}/*[contains(@id, 'ActionButton') and child::span[contains(.,'New...')]]` } get editButton() { - return `${XPATH.toolbar}/*[contains(@id, 'ActionButton') and child::span[text()='Edit']]`; + return `${XPATH.toolbarDiv}/*[contains(@id, 'ActionButton') and child::span[text()='Edit']]`; } get numberInSelectionToggler() { @@ -149,20 +142,20 @@ class ContentBrowsePanel extends BaseBrowsePanel { } get publishButton() { - return XPATH.contentPublishMenuButton + lib.actionButton('Publish...'); + return XPATH.contentActionMenuButton + lib.actionButton('Publish...'); } get unpublishButton() { - return XPATH.contentPublishMenuButton + lib.actionButton('Unpublish...'); + return XPATH.contentActionMenuButton + lib.actionButton('Unpublish...'); } get publishTreeButton() { - return XPATH.contentPublishMenuButton + lib.actionButton('Publish Tree...'); + return XPATH.contentActionMenuButton + lib.actionButton('Publish Tree...'); } get markAsReadyButton() { - return XPATH.contentPublishMenuButton + lib.actionButton('Mark as ready'); + return XPATH.contentActionMenuButton + lib.actionButton('Mark as ready'); } get displayNames() { @@ -173,8 +166,12 @@ class ContentBrowsePanel extends BaseBrowsePanel { return XPATH.container + XPATH.contentsTreeGridRootUL; } + get browseToolbar() { + return XPATH.container + XPATH.toolbarDiv; + } + get projectViewerButton() { - return "//div[contains(@id,'ContentAppBar')]" + XPATH.projectViewerButton; + return lib.DIV.CONTENT_APP_BAR_DIV + XPATH.projectViewerButton; } async clickOnProjectViewerButton() { @@ -204,7 +201,7 @@ class ContentBrowsePanel extends BaseBrowsePanel { }) } - //Wait for `Publish Menu` Button gets `Publish...` + // Wait for `Publish Menu` Button gets `Publish...` async waitForPublishButtonVisible() { try { return await this.waitForElementDisplayed(this.publishButton, appConst.mediumTimeout); @@ -214,21 +211,15 @@ class ContentBrowsePanel extends BaseBrowsePanel { } } - waitForStateIconNotDisplayed(displayName) { - let xpath = XPATH.contentSummaryByDisplayName(displayName); - return this.getBrowser().waitUntil(() => { - return this.getAttribute(xpath, 'class').then(result => { - return (!result.includes('in-progress') && !result.includes('ready')); - }); - }, {timeout: appConst.mediumTimeout, timeoutMsg: "Workflow icon is still visible in content: " + displayName}); - } - // Wait for `Publish Menu` Button gets 'Mark as ready' - waitForMarkAsReadyButtonVisible() { - return this.waitForElementDisplayed(this.markAsReadyButton, appConst.mediumTimeout).catch(err => { - this.saveScreenshot("err_publish_button_mark_as_ready"); - throw new Error("Mark as Ready button is not visible! " + err); - }) + async waitForMarkAsReadyButtonVisible() { + try { + await this.waitForElementDisplayed(this.markAsReadyButton, appConst.mediumTimeout); + await this.pause(300); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_mark_as_ready_button'); + throw new Error(`Mark as Ready button is not visible! screenshot: ${screenshot} ` + err); + } } // Wait for `Publish Menu` Button gets 'Unpublish' @@ -256,8 +247,8 @@ class ContentBrowsePanel extends BaseBrowsePanel { await unpublishDialog.pause(1000); return unpublishDialog; } catch (err) { - await this.saveScreenshot(appConst.generateRandomName("err_unpublish_button")); - throw new Error("Browse Panel toolbar - Unpublish button: " + err); + let screenshot = await this.saveScreenshotUniqueName("err_unpublish_button"); + throw new Error(`Browse Panel toolbar - Unpublish button screenshot: ${screenshot} ` + err); } } @@ -279,7 +270,7 @@ class ContentBrowsePanel extends BaseBrowsePanel { async clickOnMarkAsReadyButton() { await this.waitForMarkAsReadyButtonVisible(); await this.clickOnElement(this.markAsReadyButton); - return await this.pause(500); + return await this.pause(300); } async clickOnMoveButton() { @@ -287,8 +278,8 @@ class ContentBrowsePanel extends BaseBrowsePanel { await this.waitForMoveButtonEnabled(); return await this.clickOnElement(this.moveButton); } catch (err) { - await this.saveScreenshot(appConst.generateRandomName("err_move")); - throw new Error('error when clicking on the Move button ' + err); + let screenshot = await this.saveScreenshotUniqueName("err_move_btn"); + throw new Error(`error when clicking on the Move button, screenshot: ${screenshot} ` + err); } } @@ -326,45 +317,6 @@ class ContentBrowsePanel extends BaseBrowsePanel { return this.waitForElementDisplayed(XPATH.container + lib.SHOW_CONTEXT_PANEL_BUTTON, appConst.mediumTimeout); } - async clickOnExpanderIcon(contentName) { - try { - let expanderIcon = this.treeGrid + lib.TREE_GRID.itemTreeGridListElementByName(contentName) + lib.TREE_GRID.EXPANDER_ICON_DIV; - await this.waitForExpandToggleDisplayed(contentName); - await this.clickOnElement(expanderIcon); - return await this.pause(900); - } catch (err) { - await this.saveScreenshot('err_click_on_expander'); - throw new Error('Error occurred after clicking on expand-toggle ' + err); - } - } - - async isContentExpanded(contentName) { - try { - let divEl = this.treeGrid + lib.TREE_GRID.itemTreeGridListElementByName(contentName) + lib.TREE_GRID.EXPANDER_ICON_DIV; - await this.waitForExpandToggleDisplayed(contentName); - let attr = await this.getAttribute(divEl, 'class'); - return attr.includes('expanded'); - } catch (err) { - let screenshot = await this.saveScreenshotUniqueName('err_expander_icon'); - throw new Error(`Error occurred during checking the expand-toggle, screenshot: ${screenshot} ` + err); - } - } - - async waitForExpandToggleDisplayed(contentName) { - try { - let expanderIcon = this.treeGrid + lib.TREE_GRID.itemTreeGridListElementByName(contentName) + lib.TREE_GRID.EXPANDER_ICON_DIV; - let res = await this.findElements(expanderIcon); - if (res.length === 0) { - throw new Error('Expander icon was not found!'); - } - // check only the last element: - return await res[res.length - 1].waitForDisplayed(); - } catch (err) { - let screenshot = await this.saveScreenshotUniqueName('err_expand_toggle'); - throw new Error(`Expand toggle should be displayed! screenshot: ${screenshot} ` + err); - } - } - async clickOnShowIssuesListButton() { try { await this.waitForElementDisplayed(this.showIssuesListButton, appConst.shortTimeout); @@ -374,9 +326,10 @@ class ContentBrowsePanel extends BaseBrowsePanel { } } - //Opens Filter Panel: - clickOnSearchButton() { - return this.clickOnElement(this.searchButton); + // Opens Filter Panel: + async clickOnSearchButton() { + await this.waitForSearchButtonDisplayed(); + return await this.clickOnElement(this.searchButton); } async clickOnHideSearchPanelButton() { @@ -393,9 +346,11 @@ class ContentBrowsePanel extends BaseBrowsePanel { let contentDuplicateDialog = new ContentDuplicateDialog(); await contentDuplicateDialog.waitForDialogOpened(); await contentDuplicateDialog.waitForSpinnerNotVisible(appConst.mediumTimeout); + await contentDuplicateDialog.pause(700); return contentDuplicateDialog; } catch (err) { - throw new Error('error when clicking on the Duplicate button ' + err); + let screenshot = await this.saveScreenshotUniqueName('err_duplicate_btn_toolbar'); + throw new Error("Error after clicking on the 'Duplicate' button, screenshot: " + screenshot + ' ' + err); } } @@ -405,8 +360,8 @@ class ContentBrowsePanel extends BaseBrowsePanel { console.log("waitForContentDisplayed, timeout is:" + timeout); return await this.waitForElementDisplayed(XPATH.contentsTreeGridRootUL + lib.TREE_GRID.itemByName(contentName), timeout); } catch (err) { - let screenshot = await this.saveScreenshotUniqueName('err_find_content'); - throw new Error(`content is not displayed ! screenshot:${screenshot} ` + err); + let screenshot = await this.saveScreenshotUniqueName('err_content_displayed'); + throw new Error(`content is not displayed ! screenshot: ${screenshot} ` + err); } } @@ -426,13 +381,13 @@ class ContentBrowsePanel extends BaseBrowsePanel { await this.clickOnElement(this.previewButton); return await this.pause(2000); } catch (err) { - let screenshot = await this.saveScreenshotUniqueName("err_browsepanel_preview"); - throw new Error(`Error occurred after clicking on Preview button, screenshot:${screenshot} ` + err); + let screenshot = await this.saveScreenshotUniqueName('err_browsepanel_preview'); + throw new Error(`Error occured after clicking on 'Preview' button, screenshot: ${screenshot} ` + err); } } - isSearchButtonDisplayed() { - return this.isElementDisplayed(this.searchButton); + waitForSearchButtonDisplayed() { + return this.waitForElementDisplayed(this.searchButton, appConst.mediumTimeout); } async waitForPreviewButtonDisabled() { @@ -456,15 +411,17 @@ class ContentBrowsePanel extends BaseBrowsePanel { waitForDetailsPanelToggleButtonDisplayed() { return this.waitForElementDisplayed(this.detailsPanelToggleButton, appConst.mediumTimeout).catch(err => { this.saveScreenshot('err_details_panel_displayed'); - throw Error('Details Panel toggle button should be displayed, timeout: ' + err); + throw new Error('Details Panel toggle button should be displayed, timeout: ' + err); }) } - waitForSortButtonDisabled() { - return this.waitForElementDisabled(this.sortButton, appConst.mediumTimeout).catch(err => { - this.saveScreenshot('err_sort_disabled_button'); - throw Error('Sort button should be disabled, timeout: ' + appConst.mediumTimeout + 'ms') - }) + async waitForSortButtonDisabled() { + try { + return await this.waitForElementDisabled(this.sortButton, appConst.mediumTimeout) + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_sort_disabled_button'); + throw new Error(`Sort button should be disabled, screenshot: ${screenshot} ` + err); + } } async waitForDuplicateButtonDisabled() { @@ -473,7 +430,7 @@ class ContentBrowsePanel extends BaseBrowsePanel { return await this.waitForElementDisabled(this.duplicateButton, appConst.mediumTimeout); } catch (err) { await this.saveScreenshot('err_duplicate_disabled_button'); - throw Error('Duplicate button should be disabled, timeout: ' + 3000 + 'ms') + throw new Error('Duplicate button should be disabled, timeout: ' + 3000 + 'ms') } } @@ -483,7 +440,7 @@ class ContentBrowsePanel extends BaseBrowsePanel { return await this.waitForElementEnabled(this.duplicateButton, appConst.mediumTimeout); } catch (err) { await this.saveScreenshot('err_duplicate_should_be_enabled'); - throw Error('Duplicate button should be enabled, timeout: ' + 3000 + 'ms') + throw new Error('Duplicate button should be enabled, timeout: ' + 3000 + 'ms') } } @@ -493,7 +450,7 @@ class ContentBrowsePanel extends BaseBrowsePanel { return await this.waitForElementEnabled(this.localizeButton, appConst.mediumTimeout); } catch (err) { await this.saveScreenshot('err_localize_enabled_button'); - throw Error('Localize button should be enabled, timeout: ' + 3000 + 'ms') + throw new Error('Localize button should be enabled, timeout: ' + 3000 + 'ms') } } @@ -502,8 +459,8 @@ class ContentBrowsePanel extends BaseBrowsePanel { await this.waitForElementDisplayed(this.localizeButton, appConst.mediumTimeout); return await this.waitForElementDisabled(this.localizeButton, appConst.mediumTimeout); } catch (err) { - this.saveScreenshot('err_localize_disabled_button'); - throw Error('Localize button should be disabled, timeout: ' + 3000 + 'ms') + await this.saveScreenshot('err_localize_disabled_button'); + throw new Error('Localize button should be disabled, timeout: ' + 3000 + 'ms') } } @@ -513,7 +470,7 @@ class ContentBrowsePanel extends BaseBrowsePanel { return await this.waitForElementEnabled(this.openButton, appConst.mediumTimeout); } catch (err) { await this.saveScreenshot('err_open_button_is_not_enabled'); - throw Error('Open button should be disabled, timeout: ' + 3000 + 'ms') + throw new Error('Open button should be disabled, timeout: ' + 3000 + 'ms') } } @@ -531,7 +488,7 @@ class ContentBrowsePanel extends BaseBrowsePanel { waitForMoveButtonDisabled() { return this.waitForElementDisabled(this.moveButton, appConst.mediumTimeout).catch(err => { this.saveScreenshot('err_move_disabled_button'); - throw Error('Move button should be disabled, timeout: ' + err); + throw new Error('Move button should be disabled, timeout: ' + err); }) } @@ -547,7 +504,7 @@ class ContentBrowsePanel extends BaseBrowsePanel { waitForMoveButtonEnabled() { return this.waitForElementEnabled(this.moveButton, appConst.mediumTimeout).catch(err => { this.saveScreenshot('err_move_enabled_button'); - throw Error('Move button should be enabled, timeout: ' + err); + throw new Error('Move button should be enabled, timeout: ' + err); }) } @@ -568,8 +525,8 @@ class ContentBrowsePanel extends BaseBrowsePanel { let nameXpath = XPATH.contentsTreeGridRootUL + lib.itemByName(name); await this.waitForElementDisplayed(nameXpath, appConst.longTimeout); } catch (err) { - await this.saveScreenshot(appConst.generateRandomName('err_content')); - throw new Error("Content was not found: " + err); + let screenshot = await this.saveScreenshotUniqueName('err_content'); + throw new Error(`Content was not found: screenshot:${screenshot} ` + err); } } @@ -579,7 +536,7 @@ class ContentBrowsePanel extends BaseBrowsePanel { await this.waitForElementDisplayed(nameXpath, 3000) } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_find_content'); - throw new Error('Content was not found, screenshot ' + screenshot + " " + err); + throw new Error(`Content was not found, screenshot :${screenshot} ` + err); } } @@ -589,18 +546,17 @@ class ContentBrowsePanel extends BaseBrowsePanel { await this.waitForRowCheckboxSelected(name); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_select_item'); - throw new Error(`Error occurred during clicking on the checkbox, screenshot: ${screenshot}` + err); + throw new Error('Row with the name ' + name + ' was not selected, screenshot: ' + screenshot + ' ' + err); } } - // One or zero highlighted rows: - async getNumberOfSelectedRows() { + async clickCheckboxAndSelectRowByDisplayName(displayName) { try { - let locator = XPATH.contentsTreeGridRootUL + XPATH.highlightedRow; - let result = await this.findElements(locator); - return result.length; + await this.clickOnCheckboxByDisplayName(displayName); + return await this.pause(200); } catch (err) { - throw new Error(`Error when getting highlighted rows ` + err); + let screenshot = await this.saveScreenshotUniqueName('err_find_item'); + throw new Error(`Row with the displayName ${displayName} was not found. Screenshot: :${screenshot}` + err); } } @@ -613,6 +569,30 @@ class ContentBrowsePanel extends BaseBrowsePanel { } } + async getSortingIcon(contentName) { + + let selector = this.treeGrid + lib.TREE_GRID.itemTreeGridListElementByName(contentName) + + "//div[contains(@class,'content-tree-grid-sort')]"; + let elems = await this.findElements(selector); + let sort; + if (elems.length === 0) { + return 'Default'; + } + let classAttr = await elems[0].getAttribute('class'); + if (classAttr.includes('num-asc')) { + sort = appConst.GRID_SORTING.DATE_ASC; + } else if (classAttr.includes('num-desc')) { + sort = appConst.GRID_SORTING.DATE_DESC + } else if (classAttr.includes('alpha-asc')) { + sort = appConst.GRID_SORTING.NAME_ASC; + } else if (classAttr.includes('alpha-desc')) { + sort = appConst.GRID_SORTING.NAME_DESC; + } else if (classAttr.includes('icon-menu')) { + sort = appConst.SORT_DIALOG.MENU_ITEM.MANUALLY_SORTED; + } + return sort; + } + // returns number of rows with selected checkbox: async getNumberOfCheckedRows() { try { @@ -624,6 +604,65 @@ class ContentBrowsePanel extends BaseBrowsePanel { } } + // One or zero highlighted rows: + async getNumberOfSelectedRows() { + try { + let locator = XPATH.contentsTreeGridRootUL + XPATH.highlightedRow; + let result = await this.findElements(locator); + return result.length; + } catch (err) { + throw new Error(`Error when getting highlighted rows ` + err); + } + } + + async waitForExpandToggleDisplayed(contentName) { + try { + let expanderIcon = this.treeGrid + lib.TREE_GRID.itemTreeGridListElementByName(contentName) + lib.TREE_GRID.EXPANDER_ICON_DIV; + let res = await this.findElements(expanderIcon); + if (res.length === 0) { + throw new Error('Expander icon was not found!'); + } + // check only the last element: + return await res[res.length - 1].waitForDisplayed(); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_expand_toggle'); + throw new Error(`Expand toggle should be displayed! screenshot: ${screenshot} ` + err); + } + } + + async waitForExpandToggleNotDisplayed(contentName) { + try { + let expanderIcon = this.treeGrid + lib.TREE_GRID.itemTreeGridListElementByName(contentName) + lib.TREE_GRID.EXPANDER_ICON_DIV; + return await this.waitForElementNotDisplayed(expanderIcon, appConst.shortTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_expand_toggle'); + throw new Error(`Expand toggle should not be displayed! screenshot: ${screenshot} ` + err); + } + } + + async clickOnExpanderIcon(contentName) { + try { + let expanderIcon = this.treeGrid + lib.TREE_GRID.itemTreeGridListElementByName(contentName) + lib.TREE_GRID.EXPANDER_ICON_DIV; + await this.waitForExpandToggleDisplayed(contentName); + await this.clickOnElement(expanderIcon); + return await this.pause(900); + } catch (err) { + await this.saveScreenshot('err_click_on_expander'); + throw new Error('Error occurred after clicking on expand-toggle ' + err); + } + } + + async isContentExpanded(contentName) { + try { + let divEl = this.treeGrid + lib.TREE_GRID.itemTreeGridListElementByName(contentName) + lib.TREE_GRID.EXPANDER_ICON_DIV; + await this.waitForExpandToggleDisplayed(contentName); + let attr = await this.getAttribute(divEl, 'class'); + return attr.includes('expanded'); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_expander_icon'); + throw new Error(`Error occurred during checking the expand-toggle, screenshot: ${screenshot} ` + err); + } + } // this method does not wait, it just checks the attribute isRedIconDisplayed(contentName) { @@ -650,12 +689,20 @@ class ContentBrowsePanel extends BaseBrowsePanel { } async waitForStatus(name, expectedStatus) { - let locator = lib.TREE_GRID.itemTreeGridListElementByName(name) + lib.TREE_GRID.CONTENT_STATUS; + let locator = XPATH.container + lib.TREE_GRID.itemTreeGridListElementByName(name) + lib.TREE_GRID.CONTENT_STATUS; await this.getBrowser().waitUntil(async () => { let actualStatus = await this.getText(locator); return actualStatus === expectedStatus; }, {timeout: appConst.mediumTimeout, timeoutMsg: "Expected status should be " + expectedStatus}); + } + async waitForStatusByDisplayName(displayName, expectedStatus) { + let locator = lib.TREE_GRID.contentSummaryByDisplayName(XPATH.container, displayName) + "/.." + lib.TREE_GRID.CONTENT_STATUS; + let res = await this.findElements(locator); + await this.getBrowser().waitUntil(async () => { + let actualStatus = await this.getText(locator); + return actualStatus === expectedStatus; + }, {timeout: appConst.mediumTimeout, timeoutMsg: "Expected status should be " + expectedStatus}); } waitForShowPublishMenuDropDownVisible() { @@ -689,16 +736,16 @@ class ContentBrowsePanel extends BaseBrowsePanel { async waitForPublishMenuItemDisabled(menuItem) { try { - let selector = XPATH.toolbar + XPATH.publishMenuItemByName(menuItem); + let selector = XPATH.toolbarDiv + XPATH.publishMenuItemByName(menuItem); return await this.waitForAttributeHasValue(selector, "class", "disabled"); } catch (err) { - await this.saveScreenshot("err_publish_menuItem"); + await this.saveScreenshot('err_publish_menuItem'); throw new Error(menuItem + " should be disabled! " + err); } } async waitForPublishMenuItemEnabled(menuItem) { - let selector = XPATH.toolbar + XPATH.publishMenuItemByName(menuItem); + let selector = XPATH.toolbarDiv + XPATH.publishMenuItemByName(menuItem); return await this.waitForAttributeNotIncludesValue(selector, "class", "disabled"); } @@ -711,12 +758,12 @@ class ContentBrowsePanel extends BaseBrowsePanel { try { await this.waitForShowPublishMenuDropDownVisible(); await this.clickOnElement(this.showPublishMenuButton); - let selector = XPATH.toolbar + XPATH.publishMenuItemByName(menuItem); + let selector = XPATH.toolbarDiv + XPATH.publishMenuItemByName(menuItem); await this.waitForPublishMenuItemEnabled(menuItem); await this.clickOnElement(selector); return await this.pause(300); } catch (err) { - await this.saveScreenshot("err_click_issue_menuItem"); + await this.saveScreenshot('err_click_issue_menuItem'); throw new Error('error when try to click on publish menu item, ' + err); } } @@ -751,7 +798,7 @@ class ContentBrowsePanel extends BaseBrowsePanel { // finds workflow state by a display name async getWorkflowStateByDisplayName(displayName) { - let xpath = lib.TREE_GRID.contentStatusByDisplayName(XPATH.container, displayName); + let xpath = XPATH.selectableListBoxPanelDiv + lib.TREE_GRID.contentSummaryByDisplayName(XPATH.container, displayName); await this.waitForElementDisplayed(xpath, appConst.shortTimeout); let result = await this.getAttribute(xpath, 'class'); if (result.includes('in-progress')) { @@ -766,9 +813,9 @@ class ContentBrowsePanel extends BaseBrowsePanel { } } - // finds workflow state by the name + // finds workflow state by a name async getWorkflowStateByName(name) { - let xpath = lib.TREE_GRID.contentStatusByName(name); + let xpath = XPATH.selectableListBoxPanelDiv + lib.TREE_GRID.contentSummaryByName(name); await this.waitForElementDisplayed(xpath, appConst.shortTimeout); let result = await this.getAttribute(xpath, 'class'); if (result.includes('in-progress')) { @@ -784,10 +831,10 @@ class ContentBrowsePanel extends BaseBrowsePanel { async waitForDefaultAction(actionName) { try { - let selector = XPATH.contentPublishMenuButton + XPATH.defaultActionByName(actionName); + let selector = XPATH.contentActionMenuButton + XPATH.defaultActionByName(actionName); return await this.waitForElementDisplayed(selector, appConst.mediumTimeout); } catch (err) { - throw Error(`Publish Menu - '${actionName}' this default action should be visible!: ` + err); + throw new Error(`Publish Menu - '${actionName}' this default action should be visible!: ` + err); } } @@ -831,22 +878,27 @@ class ContentBrowsePanel extends BaseBrowsePanel { async isContentInherited(contentName) { await this.waitForContentDisplayed(contentName, appConst.mediumTimeout); - let locator = lib.TREE_GRID.contentStatusByName(contentName) + let locator = lib.TREE_GRID.contentSummaryByName(contentName) let attr = await this.getAttribute(locator, 'class'); return attr.includes('data-inherited'); } - async isContentByDisplayNameInherited(contentName) { - await this.waitForContentDisplayed(contentName, appConst.mediumTimeout); - let locator = lib.TREE_GRID.contentStatusByDisplayName(XPATH.container, contentName); + async isContentByDisplayNameInherited(contentDisplayName) { + await this.waitForContentDisplayed(contentDisplayName, appConst.mediumTimeout); + let locator = lib.TREE_GRID.contentSummaryByDisplayName(XPATH.container, contentDisplayName); let attr = await this.getAttribute(locator, 'class'); return attr.includes('data-inherited'); } async clickOnLocalizeButton() { - await this.waitForElementEnabled(this.localizeButton, appConst.mediumTimeout); - await this.clickOnElement(this.localizeButton); - return await this.pause(1000); + try { + await this.waitForElementEnabled(this.localizeButton, appConst.mediumTimeout); + await this.clickOnElement(this.localizeButton); + return await this.pause(1000); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_localize_btn'); + throw new Error(`Content Browse Panel, Localize button, screenshot:${screenshot} ` + err); + } } async rightClickOnItemByDisplayName(displayName) { @@ -871,7 +923,7 @@ class ContentBrowsePanel extends BaseBrowsePanel { await this.waitForElementEnabled(this.archiveButton, appConst.mediumTimeout); } catch (err) { await this.saveScreenshot('err_delete_button'); - throw Error("Archive button should be enabled " + err); + throw new Error("Archive button should be enabled " + err); } } @@ -886,28 +938,6 @@ class ContentBrowsePanel extends BaseBrowsePanel { return await this.pause(500); } - async isContentExpanded(contentName) { - try { - let locator = XPATH.expanderIconByName(contentName); - await this.waitForExpanderIconDisplayed(contentName); - let attr = await this.getAttribute(locator, "class"); - return attr.includes("collapse"); - } catch (err) { - await this.saveScreenshot(appConst.generateRandomName('err_expander_icon')); - throw new Error("Toggle icon: " + err); - } - } - - waitForExpanderIconDisplayed(contentName) { - let locator = XPATH.expanderIconByName(contentName); - return this.waitForElementDisplayed(locator, appConst.mediumTimeout); - } - - waitForExpanderIconNotDisplayed(contentName) { - let locator = XPATH.expanderIconByName(contentName); - return this.waitForElementNotDisplayed(locator, appConst.mediumTimeout); - } - getDisplayNameInHighlightedRow() { let locator = XPATH.highlightedRow + lib.H6_DISPLAY_NAME; return this.getText(locator); @@ -947,29 +977,34 @@ class ContentBrowsePanel extends BaseBrowsePanel { return await this.waitForElementDisplayed(selector, appConst.mediumTimeout); } + async waitForGridRoleAttribute(expectedRole) { + let locator = XPATH.treeGrid; + await this.getBrowser().waitUntil(async () => { + let text = await this.getAttribute(locator, "role"); + return text === expectedRole; + }, {timeout: appConst.shortTimeout, timeoutMsg: "Role attribute for Grid should set 'grid'"}); + } + async waitForVariantIconDisplayed(name) { let listElements = lib.TREE_GRID.itemTreeGridListElementByName(name); let result = await this.findElements(listElements); if (result.length === 0) { - throw new Error('Checkbox was not found!'); + throw new Error('Content item was not found!'); } // get the last element(skip the root element) - let listElement = result[result.length - 1]; - let contentSummaryViewer = await listElement.$('.' + lib.DIV.CONTENT_SUMMARY_AND_STATUS_VIEWER); - await this.getBrowser().waitUntil(async () => { - let atr = await contentSummaryViewer.getAttribute('class'); - return atr.includes('icon-variant'); - }, {timeout: appConst.mediumTimeout, timeoutMsg: 'Variant icon is not displayed in the grid'}); - } - - async clickCheckboxAndSelectRowByDisplayName(displayName) { - try { - await this.clickOnCheckboxByDisplayName(displayName); - return await this.pause(200); - } catch (err) { - let screenshot = await this.saveScreenshotUniqueName('err_find_item'); - throw new Error(`Row with the displayName ${displayName} was not found. Screenshot:` + screenshot + ' ' + err); - } + // let listElement = result[result.length - 1]; + // let contentSummaryViewer = await listElement.$('.' + lib.DIV.CONTENT_SUMMARY_AND_STATUS_VIEWER); + // let class1 = await contentSummaryViewer.getAttribute("class") + // let id= await contentSummaryViewer.getAttribute("id") + // await this.getBrowser().waitUntil(async () => { + // let atr = await contentSummaryViewer.getAttribute('class'); + // return atr.includes('icon-variant'); + // }, {timeout: appConst.mediumTimeout, timeoutMsg: 'Variant icon is not displayed in the grid'}); + + let locator = lib.TREE_GRID.contentSummaryByName(name);// + lib.DIV.CONTENT_SUMMARY_AND_STATUS_VIEWER; + let element = await this.findElement(locator); + let atr = await element.getAttribute("class") + return atr.includes('icon-variant'); } } diff --git a/testing/page_objects/browsepanel/content.filter.panel.js b/testing/page_objects/browsepanel/content.filter.panel.js index e957f19e..092c105b 100644 --- a/testing/page_objects/browsepanel/content.filter.panel.js +++ b/testing/page_objects/browsepanel/content.filter.panel.js @@ -4,38 +4,172 @@ const Page = require('../page'); const appConst = require('../../libs/app_const'); const lib = require('../../libs/elements'); +const FilterableListBox = require('../components/selectors/filterable.list.box'); + const XPATH = { container: "//div[contains(@id,'ContentBrowseFilterPanel')]", - clearFilterButton: "//a[contains(@id,'ClearFilterButton']", + hitsAndClearDiv: "//div[contains(@class,'hits-and-clear')]", + clearFilterLink: "//a[contains(@id,'ClearFilterButton')]", searchInput: "//input[contains(@id,'TextSearchField')]", dependenciesSection: "//div[contains(@id,'DependenciesSection')]", - aggregationContainer: "//div[contains(@id,'AggregationContainer')]//div[contains(@id,'ContentTypeAggregationGroupView')]", - aggregationLabelByName: name => XPATH.aggregationContainer + - `//div[contains(@class,'checkbox') and child::label[contains(.,'${name}')]]//label`, - aggregationCheckboxByName: name => XPATH.aggregationContainer + - `//div[contains(@class,'checkbox') and child::label[contains(.,'${name}')]]` + lib.CHECKBOX_INPUT, + showResultsButton: "//span[contains(@class,'show-filter-results')]", + showMoreButton: "//button[child::span[text()='Show more']]", + showLessButton: "//button[child::span[text()='Show less']]", + selectorOptionCheckbox: "//ul[contains(@id,'BucketListBox')]//div[contains(@id,'Checkbox')]", + selectorOptionItem: "//ul[contains(@id,'BucketListBox')]//div[contains(@class,'item-view-wrapper')]", + selectorOptionItemByLabel: label => `//ul[contains(@id,'BucketListBox')]//div[contains(@class,'item-view-wrapper') and descendant::h6[contains(@class,'main-name') and contains(.,'${label}')]]`, + ownerAggregationGroupView: "//div[contains(@id,'FilterableAggregationGroupView') and child::h2[text()='Owner']]", + lastModifiedByAggregationGroupView: "//div[contains(@id,'FilterableAggregationGroupView') and child::h2[text()='Last Modified by']]", + aggregationGroupByName: name => `//div[contains(@id,'AggregationContainer')]//div[contains(@id,'AggregationGroupView') and child::h2[text()='${name}']]`, + aggregationLabelByName: name => `//div[contains(@class,'checkbox') and child::label[contains(.,'${name}')]]//label`, + folderAggregation: () => `//div[contains(@class,'checkbox') and child::label[contains(.,'Folder') and not(contains(.,'Template'))]]//label`, + aggregationCheckboxByName: name => `//div[contains(@class,'checkbox') and child::label[contains(.,'${name}')]]` + lib.CHECKBOX_INPUT, + lastModifiedAggregationEntry: + time => `//div[@class='aggregation-group-view']/h2[text()='Last Modified']/..//div[contains(@class,'checkbox') and child::label]//label[contains(.,'${time}')]`, }; class BrowseFilterPanel extends Page { get clearFilterLink() { - return XPATH.container + XPATH.clearFilterButton; + return XPATH.container + XPATH.clearFilterLink; + } + + get exportButton() { + return XPATH.container + XPATH.hitsAndClearDiv + "//span[contains(@id,'ContentExportElement')]"; + } + + get showResultsButton() { + return XPATH.container + XPATH.showResultsButton; + } + + get showMoreButton() { + return XPATH.container + "//div[contains(@id,'AggregationGroupView') and child::h2[text()='Content Types']]" + XPATH.showMoreButton; + } + + get showLessButton() { + return XPATH.container + "//div[contains(@id,'AggregationGroupView') and child::h2[text()='Content Types']]" + XPATH.showLessButton; + } + + + get closeDependenciesSectionButtonLocator() { + return XPATH.dependenciesSection + "//button[contains(@class,'btn-close')]"; } get searchTextInput() { return XPATH.container + XPATH.searchInput; } + async typeSearchText(text) { try { - return await this.typeTextInInput(this.searchTextInput, text); + await this.typeTextInInput(this.searchTextInput, text); + return await this.pause(500); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_filter_input'); + throw new Error("Error when type text in Search Input, screenshot: " + screenshot + ' ' + err); + } + } + + async waitForExportButtonDisplayed() { + try { + return await this.waitForElementDisplayed(this.exportButton, appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_export_btn'); + throw new Error("Error - Export button should be displayed, screenshot: " + screenshot + ' ' + err); + } + } + + async waitForExportButtonNotDisplayed() { + try { + return await this.waitForElementNotDisplayed(this.exportButton, appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_export_btn'); + throw new Error("Error - Export button should not be displayed, screenshot: " + screenshot + ' ' + err); + } + } + + async waitForExportButtonDisabled() { + try { + await this.getBrowser().waitUntil(async () => { + let text = await this.getAttribute(this.exportButton, "class"); + return text.includes('disabled'); + }, {timeout: appConst.shortTimeout, timeoutMsg: "'Export' button should be disabled"}); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_export_btn'); + throw new Error("Error - Export button should be disabled, screenshot: " + screenshot + ' ' + err); + } + } + + async waitForExportButtonEnabled() { + try { + await this.waitForExportButtonDisplayed(); + await this.getBrowser().waitUntil(async () => { + let text = await this.getAttribute(this.exportButton, "class"); + return !text.includes('disabled'); + }, {timeout: appConst.shortTimeout, timeoutMsg: "'Export' button should be enabled"}); } catch (err) { - throw new Error("Error when type text in Search Input " + err); + let screenshot = await this.saveScreenshotUniqueName('err_export_btn'); + throw new Error("Error - Export button should be enabled, screenshot: " + screenshot + ' ' + err); } } - waitForOpened() { - return this.waitForElementDisplayed(XPATH.container, appConst.mediumTimeout); + async clickOnExportButton() { + await this.waitForExportButtonEnabled(); + await this.clickOnElement(this.exportButton); + } + + async waitForOpened() { + await this.waitForElementDisplayed(XPATH.container, appConst.mediumTimeout); + await this.pause(300); + } + + waitForShowResultsButtonDisplayed() { + return this.waitForElementDisplayed(this.showResultsButton, appConst.mediumTimeout); + } + + waitForShowMoreButtonDisplayed() { + return this.waitForElementDisplayed(this.showMoreButton, appConst.shortTimeout); + } + + waitForShowMoreButtonNotDisplayed() { + return this.waitForElementNotDisplayed(this.showMoreButton, appConst.shortTimeout); + } + + async clickOnShowMoreButton() { + await this.waitForShowMoreButtonDisplayed(); + return await this.clickOnElement(this.showMoreButton); + } + + isShowMoreButtonDisplayed() { + return this.isElementDisplayed(this.showMoreButton) + } + + waitForShowLessButtonDisplayed() { + return this.waitForElementDisplayed(this.showLessButton, appConst.shortTimeout); + } + + waitForShowLessButtonNotDisplayed() { + return this.waitForElementNotDisplayed(this.showLessButton, appConst.shortTimeout); + } + + async clickOnShowResultsButton() { + try { + await this.waitForShowResultsButtonDisplayed(); + return await this.clickOnElement(this.showResultsButton); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_show_results_button'); + throw new Error("Error when click on Show Results button, screenshot: " + screenshot + ' ' + err); + } + } + + async waitForCloseDependenciesSectionButtonDisplayed() { + try { + let el = await this.findElements(this.closeDependenciesSectionButtonLocator); + return await this.waitForElementDisplayed(this.closeDependenciesSectionButtonLocator, appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_close_dependencies_section_btn'); + throw new Error("Error Close dependencies section should be displayed, screenshot: " + screenshot + ' ' + err); + } } isPanelVisible() { @@ -46,25 +180,27 @@ class BrowseFilterPanel extends Page { return this.waitForElementDisplayed(this.clearFilterLink, appConst.mediumTimeout) } - waitForDependenciesSectionVisible() { - return this.waitForElementDisplayed(XPATH.container + XPATH.dependenciesSection, appConst.mediumTimeout).catch(err => { - this.saveScreenshot("err_load_dependencies_section"); - throw new Error(" Filter Panel: Dependencies section should be visible! " + err); - }) + waitForClearLinkNotDisplayed() { + return this.waitForElementNotDisplayed(this.clearFilterLink, appConst.mediumTimeout) } - clickOnClearLink() { - return this.clickOnElement(this.clearFilterLink) + async waitForDependenciesSectionVisible(ms) { + try { + let timeout; + timeout = ms === undefined ? appConst.mediumTimeout : ms; + return await this.waitForElementDisplayed(XPATH.container + XPATH.dependenciesSection, timeout) + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_load_dependencies_section'); + throw new Error("Filter Panel: Dependencies section should be visible! screenshot " + screenshot + ' ' + err); + } } - async clickOnCheckboxInAggregationView(contentType) { - let selector = XPATH.aggregationLabelByName(contentType); - await this.waitForElementDisplayed(selector, appConst.shortTimeout); - await this.clickOnElement(selector); - return await this.pause(400); + async clickOnClearLink() { + await this.waitForClearLinkDisplayed(); + await this.clickOnElement(this.clearFilterLink) + await this.pause(1000); } - //clicks on a checkbox in Content Types aggregation block async clickOnCheckboxInContentTypesBlock(contentType) { try { @@ -78,9 +214,176 @@ class BrowseFilterPanel extends Page { await this.clickOnElement(selector); return await this.pause(1200); } catch (err) { - await this.saveScreenshot(appConst.generateRandomName("err_content_types_filtering")); - throw new Error("Error after clicking on a checkbox in Content Types aggregation block " + err); + let screenshot = await this.saveScreenshotUniqueName('err_content_types_filtering'); + throw new Error("Error, checkbox in Content Types aggregation block, screenshot " + screenshot + ' ' + err); + } + } + + async waitForCheckboxDisplayed(blockName, label) { + let selector = XPATH.aggregationGroupByName(blockName) + XPATH.aggregationLabelByName(label); + return await this.waitForElementDisplayed(selector, appConst.mediumTimeout); + } + + async waitForAggregationGroupDisplayed(blockName) { + let selector = XPATH.aggregationGroupByName(blockName); + return await this.waitForElementDisplayed(selector, appConst.mediumTimeout); + } + + async waitForCheckboxNotDisplayed(blockName, checkBoxLabel) { + let selector = XPATH.aggregationGroupByName(blockName) + XPATH.aggregationLabelByName(checkBoxLabel); + return await this.waitForElementNotDisplayed(selector, appConst.mediumTimeout); + } + + // clicks on a checkbox in Workflow aggregation block + async clickOnCheckboxInWorkflowBlock(checkBoxLabel) { + try { + let selector = XPATH.aggregationGroupByName(appConst.FILTER_PANEL_AGGREGATION_BLOCK.WORKFLOW) + + XPATH.aggregationLabelByName(checkBoxLabel); + await this.waitForElementDisplayed(selector, appConst.shortTimeout); + await this.clickOnElement(selector); + return await this.pause(1200); + } catch (err) { + await this.saveScreenshot(appConst.generateRandomName("err_click_on_aggregation")); + throw new Error("Error when click on the aggregation checkbox: " + err); + } + } + + async clickOnCheckboxInLanguageBlock(checkBoxLabel) { + try { + let selector = XPATH.aggregationGroupByName(appConst.FILTER_PANEL_AGGREGATION_BLOCK.LANGUAGE) + + XPATH.aggregationLabelByName(checkBoxLabel); + await this.waitForElementDisplayed(selector, appConst.shortTimeout); + await this.clickOnElement(selector); + return await this.pause(1200); + } catch (err) { + await this.saveScreenshot(appConst.generateRandomName("err_click_on_aggregation")); + throw new Error('Error when click on the aggregation checkbox: ' + err); + } + } + + // gets a number of items from a checkbox label in an aggregation block(Workflow,modifier) + async getNumberOfItemsInAggregationView(blockName, checkboxLabel, showMore) { + if (typeof showMore !== 'undefined') { + if (showMore && await this.isShowMoreButtonDisplayed()) { + await this.clickOnShowMoreButton(); + } + } + try { + let locator = XPATH.aggregationGroupByName(blockName) + XPATH.aggregationLabelByName(checkboxLabel); + await this.waitForElementDisplayed(locator, appConst.shortTimeout); + let label = await this.getText(locator); + let startIndex = label.indexOf('('); + let endIndex = label.indexOf(')'); + return label.substring(startIndex + 1, endIndex); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_numb_in_aggregation'); + throw new Error('Error, get the number in aggregation checkbox, screenshot: ' + screenshot + ' ' + err); } } + + // gets a number of items from a checkbox label in Folder aggregation : + async getNumberOfItemsInFolderAggregation() { + let locator = XPATH.folderAggregation(); + await this.waitForElementDisplayed(locator, appConst.shortTimeout); + let label = await this.getText(locator); + let startIndex = label.indexOf('('); + let endIndex = label.indexOf(')'); + return label.substring(startIndex + 1, endIndex); + } + + // Gets display name of items in "Content Types" block: + async geContentTypes() { + let locator = XPATH.aggregationGroupByName('Content Types') + "//div[contains(@class,'checkbox')]//label"; + await this.waitForElementDisplayed(locator, appConst.shortTimeout); + return await this.getTextInDisplayedElements(locator); + } + + // Gets number of items in "Last Modified" week/day/hour + async getLastModifiedCount(timestamp) { + let locator = XPATH.lastModifiedAggregationEntry(timestamp); + await this.waitForElementDisplayed(locator, appConst.shortTimeout); + let label = await this.getText(locator); + let startIndex = label.indexOf('('); + let endIndex = label.indexOf(')'); + return label.substring(startIndex + 1, endIndex); + } + + // Expands the 'Owner' dropdown: + async clickOnOwnerDropdownHandle() { + let filterableListBox = new FilterableListBox(); + await filterableListBox.clickOnDropdownHandle(XPATH.ownerAggregationGroupView); + await this.pause(500); + } + + // gets options name from the 'Owner' list box: + async getOwnerNameInSelector() { + let owners = []; + let filterableListBox = new FilterableListBox(); + let optionNames = await filterableListBox.getOptionsDisplayName(XPATH.ownerAggregationGroupView); + optionNames.map(item => { + let value = item.substring(0, item.indexOf('(')); + owners.push(value.trim()); + }) + return owners; + } + + // Selects an option in 'Owner' dropdown: types the name in the filter input and clicks on the filtered option + async filterAndSelectOwnerOption(ownerName) { + try { + let filterableListBox = new FilterableListBox(); + await filterableListBox.clickOnFilteredByDisplayNameItemAndClickOnApply(ownerName, XPATH.ownerAggregationGroupView); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_filter_owner'); + throw new Error("Error occurred during selecting an option in 'Owner Selector', screenshot: " + screenshot + ' ' + err); + } + } + + // Expands the 'Last Modified By' dropdown: + async clickOnLastModifiedByDropdownHandle() { + let filterableListBox = new FilterableListBox(); + await filterableListBox.clickOnDropdownHandle(XPATH.lastModifiedByAggregationGroupView); + } + + async isCheckedInLastModifiedByListOptions(userName) { + let locator = XPATH.lastModifiedByAggregationGroupView + lib.DROPDOWN_SELECTOR.listItemByDisplayName(userName) + + lib.CHECKBOX_INPUT; + let chElement = await this.findElements(locator); + return await chElement[0].isSelected(); + } + + async uncheckItemInLastModifiedByListBox(userName) { + let locator = XPATH.lastModifiedByAggregationGroupView + lib.DROPDOWN_SELECTOR.listItemByDisplayName(userName); + let chElement = await this.findElements(locator); + await chElement[0].click(); + let filterableListBox = new FilterableListBox(); + await filterableListBox.clickOnApplySelectionButton(XPATH.lastModifiedByAggregationGroupView); + } + + // Selects an option in 'Last Modified By' dropdown: + async filterAndSelectLastModifiedByOption(userName) { + try { + let filterableListBox = new FilterableListBox(); + // 1. insert the username in the filter input: + await this.filterItemInModifiedBy(userName); + let optionLocator = filterableListBox.buildLocatorForOptionByDisplayName(userName, XPATH.lastModifiedByAggregationGroupView); + await this.waitForElementDisplayed(optionLocator, appConst.mediumTimeout); + // 2. Click on the option-item, select the user in the dropdown: + await this.clickOnElement(optionLocator); + // 3. Click on 'OK' button and apply the selection: + return await filterableListBox.clickOnApplySelectionButton(); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_filter_modified_by'); + throw new Error("Error occurred during selecting an option in 'Modified by Selector', screenshot: " + screenshot + ' ' + err); + } + } + + async filterItemInModifiedBy(text) { + let locator = XPATH.lastModifiedByAggregationGroupView + lib.OPTION_FILTER_INPUT; + await this.waitUntilDisplayed(locator, appConst.mediumTimeout); + let elements = await this.getDisplayedElements(locator); + await elements[0].setValue(text); + return await this.pause(300); + } } -module.exports = BrowseFilterPanel; \ No newline at end of file + +module.exports = BrowseFilterPanel; diff --git a/testing/page_objects/browsepanel/contentItem.preview.panel.js b/testing/page_objects/browsepanel/contentItem.preview.panel.js index 1e7c18e6..886bd3ed 100644 --- a/testing/page_objects/browsepanel/contentItem.preview.panel.js +++ b/testing/page_objects/browsepanel/contentItem.preview.panel.js @@ -11,6 +11,8 @@ const xpath = { status: `//div[contains(@class,'content-status-wrapper')]/span[contains(@class,'status')]`, author: `//div[contains(@class,'content-status-wrapper')]/span[contains(@class,'author')]`, issueMenuButton: `//div[contains(@id,'MenuButton')]`, + showChangesButtonToolbar: "//button[contains(@class,'show-changes') and @title='Show changes']", + previewNotAvailableSpan: "//div[@class='no-preview-message']//span[text()='Preview not available']", issueMenuItemByName: name => `//ul[contains(@id,'Menu')]/li[contains(@id,'MenuItem') and contains(.,'${name}')]`, issueMenuButtonByName: @@ -27,13 +29,43 @@ class ContentItemPreviewPanel extends Page { return xpath.toolbar + xpath.status; } + get previewNotAvailableMessage() { + return xpath.container + xpath.previewNotAvailableSpan; + } + get author() { return xpath.toolbar + xpath.author; } + get showChangesToolbarButton() { + return xpath.toolbar + xpath.showChangesButtonToolbar; + } + + waitForShowChangesButtonDisplayed() { + return this.waitForElementDisplayed(this.showChangesToolbarButton, appConst.mediumTimeout); + } + + waitForShowChangesButtonNotDisplayed() { + return this.waitForElementNotDisplayed(this.showChangesToolbarButton, appConst.mediumTimeout); + } + + async clickOnShowChangesToolbarButton() { + await this.waitForShowChangesButtonDisplayed(); + await this.clickOnElement(this.showChangesToolbarButton); + } + + waitForPreviewNotAvailAbleMessageDisplayed() { + return this.waitForElementDisplayed(this.previewNotAvailableMessage, appConst.mediumTimeout); + } + + async waitForImageDisplayed() { + let locator = xpath.container + "//img"; + return await this.waitForElementDisplayed(locator, appConst.mediumTimeout); + } + waitForPanelVisible() { return this.waitForElementDisplayed(xpath.container, appConst.shortTimeout).catch(err => { - throw new Error('Content Item preview toolbar was not loaded in ' + appConst.shortTimeout); + throw new Error('Content Item preview toolbar was not loaded ' + err); }); } @@ -53,7 +85,8 @@ class ContentItemPreviewPanel extends Page { await this.waitForIssueDropDownHandleDisplayed(); return await this.clickOnElement(this.issueDropdownHandle); } catch (err) { - throw new Error('error when clicking on the dropdown handle ' + err); + let screenshot = await this.saveScreenshotUniqueName('err_issue_dropdown'); + throw new Error(`error after clicking on the dropdown handle , screenshot: ${screenshot}` + err); } } @@ -64,7 +97,6 @@ class ContentItemPreviewPanel extends Page { waitForIssueDropDownHandleNotDisplayed() { return this.waitForElementNotDisplayed(this.issueDropdownHandle, appConst.shortTimeout).catch(err => { throw new Error('Item Preview Toolbar - dropdown handle should not be displayed ! ' + err); - }); } @@ -74,19 +106,19 @@ class ContentItemPreviewPanel extends Page { await this.waitForElementDisplayed(selector, appConst.mediumTimeout); return await this.clickOnElement(selector); } catch (err) { - this.saveScreenshot("err_issue_menu_item"); - throw new Error("Menu item was not found! " + issueName + " " + err); + let screenshot = await this.saveScreenshotUniqueName('err_issue_menu_item'); + throw new Error(`Menu item was not found! screenshot: ${screenshot} ` + err); } } - //When issue is closed, this button gets not visible: + // When issue is closed, this button gets not visible: async waitForIssueMenuButtonNotVisible() { try { let selector = xpath.toolbar + `//div[contains(@id,'MenuButton') and descendant::span[contains(@class,'icon-issue')]]//button`; await this.waitForElementNotDisplayed(selector, appConst.mediumTimeout); } catch (err) { - this.saveScreenshot("err_preview_toolbar_issue_icon"); - throw new Error("Issue icon still visible in the toolbar " + err); + let screenshot = await this.saveScreenshotUniqueName('err_preview_toolbar_issue_icon'); + throw new Error(`Issue icon should not be visible in the toolbar, screenshot: ${screenshot} ` + err); } } @@ -97,7 +129,8 @@ class ContentItemPreviewPanel extends Page { await this.clickOnElement(selector); return await this.pause(400); } catch (err) { - throw new Error('issue menu button was not found! ' + err); + let screenshot = await this.saveScreenshotUniqueName('err_preview_toolbar_issue_icon'); + throw new Error(`Issue menu button was not found! screenshot: ${screenshot} ` + err); } } @@ -108,18 +141,26 @@ class ContentItemPreviewPanel extends Page { await this.clickOnElement(locator); return await this.pause(400); } catch (err) { - throw new Error('issue menu button was not found! ' + err); + let screenshot = await this.saveScreenshotUniqueName('err_preview_toolbar_issue_icon'); + throw new Error(`Issue menu button was not found! screenshot: ${screenshot} ` + err); } } async getContentStatus() { let result = await this.getDisplayedElements(this.contentStatus); - return await result[0].getText(this.contentStatus); + if (result.length === 0) { + throw new Error("Content status is not displayed: "); + } + return await result[0].getText(); } - async getContentAuthor() { - let result = await this.getDisplayedElements(this.author); - return await result[0].getText(); + async waitForAuthorNotDisplayed() { + try { + return await this.waitForElementNotDisplayed(this.author, appConst.mediumTimeout); + } catch (err) { + await this.saveScreenshot(appConst.generateRandomName("err_itempreview_author")); + throw new Error("Author should not be displayed in the item preview toolbar " + err); + } } async getIssueNameInMenuButton() { @@ -145,7 +186,7 @@ class ContentItemPreviewPanel extends Page { await this.switchToFrame(xpath.container + "//iframe[contains(@src,'admin/site')]"); let result = await this.waitForElementNotDisplayed(selector, appConst.mediumTimeout); await this.switchToParentFrame(); - return result + return result; } catch (err) { await this.switchToParentFrame(); return false; @@ -168,7 +209,7 @@ class ContentItemPreviewPanel extends Page { return this.waitUntilDisplayed(selector, appConst.shortTimeout); } - //switches to iframe and gets text in the panel + // switches to iframe and gets text in the panel async getTextInAttachmentPreview() { try { let attachmentFrame = "//iframe[contains(@src,'/admin/rest-v2/cs/cms/default/content/content/media/')]"; @@ -178,6 +219,29 @@ class ContentItemPreviewPanel extends Page { throw new Error("Content Item Preview Panel - " + err); } } + + async getNoPreviewMessage() { + let locator = xpath.container + "//div[@class='no-preview-message']//span"; + await this.waitForElementDisplayed(locator, appConst.mediumTimeout); + return await this.getTextInDisplayedElements(locator); + } + + async waitForToolbarRoleAttribute(expectedRole) { + let locator = xpath.toolbar; + await this.getBrowser().waitUntil(async () => { + let text = await this.getAttribute(locator, 'role'); + return text === expectedRole; + }, {timeout: appConst.shortTimeout, timeoutMsg: "Content Item preview toolbar should be with 'role=toolbar' attribute"}); + } + + // check for Accessibility attributes: aria-label + async waitForBrowseToolbarAriaLabelAttribute(expectedValue) { + let locator = xpath.toolbar; + await this.getBrowser().waitUntil(async () => { + let text = await this.getAttribute(locator, "aria-label"); + return text === expectedValue; + }, {timeout: appConst.shortTimeout, timeoutMsg: "Content Item preview toolbar should contain expected 'aria-label' attribute"}); + } } module.exports = ContentItemPreviewPanel; diff --git a/testing/page_objects/browsepanel/detailspanel/browse.dependencies.widget.js b/testing/page_objects/browsepanel/detailspanel/browse.dependencies.widget.js index 25ffc549..998138be 100644 --- a/testing/page_objects/browsepanel/detailspanel/browse.dependencies.widget.js +++ b/testing/page_objects/browsepanel/detailspanel/browse.dependencies.widget.js @@ -28,12 +28,17 @@ class BrowseDependenciesWidget extends BaseDependenciesWidget { return this.isElementDisplayed(this.dependenciesWidget); } - waitForWidgetLoaded() { - return this.waitForElementDisplayed(this.dependenciesWidget, appConst.shortTimeout).catch(err => { - throw new Error('Content Wizard: Dependencies Widget was not loaded in ' + appConst.shortTimeout); - }); + async waitForWidgetLoaded() { + try { + await this.waitForElementDisplayed(this.dependenciesWidget, appConst.shortTimeout); + await this.pause(400); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_widget_load'); + throw new Error(`Content Wizard: Dependencies Widget was not screenshot:${screenshot} ` + err); + } } } + module.exports = BrowseDependenciesWidget; diff --git a/testing/page_objects/browsepanel/detailspanel/browse.details.panel.js b/testing/page_objects/browsepanel/detailspanel/browse.details.panel.js index 013e46c8..18644303 100644 --- a/testing/page_objects/browsepanel/detailspanel/browse.details.panel.js +++ b/testing/page_objects/browsepanel/detailspanel/browse.details.panel.js @@ -37,6 +37,11 @@ class BrowseDetailsPanel extends BaseDetailsPanel { }) }, {timeout: appConst.shortTimeout, timeoutMsg: "Details Panel should be cleared"}); } + + async waitForWidgetDropdownRoleAttribute(expectedValue) { + let locator = this.widgetSelectorDropdownHandle; + await this.waitForAttributeValue(locator, appConst.ACCESSIBILITY_ATTRIBUTES.ROLE, expectedValue); + } } module.exports = BrowseDetailsPanel; diff --git a/testing/page_objects/browsepanel/detailspanel/browse.versions.widget.js b/testing/page_objects/browsepanel/detailspanel/browse.versions.widget.js index f1d8eea6..2fb2446a 100644 --- a/testing/page_objects/browsepanel/detailspanel/browse.versions.widget.js +++ b/testing/page_objects/browsepanel/detailspanel/browse.versions.widget.js @@ -6,8 +6,16 @@ const BaseVersionsWidget = require('../../details_panel/base.versions.widget'); const XPATH = { widget: "//div[contains(@id,'ContentBrowsePanel')]//div[contains(@id,'VersionHistoryView')]", versionsList: "//ul[contains(@id,'VersionHistoryList')]", - versionItem: "//li[contains(@class,'version-list-item') and child::div[contains(@class,'version-viewer')]]", - publishedItems: "//li[contains(@id,'VersionHistoryListItem')and descendant::h6[contains(.,'Published')]]", + versionsListItem: "//li[contains(@class,'version-list-item')]", + editedListItem: "//li[contains(@class,'version-list-item') and child::div[not(contains(@class,'publish-action'))] and descendant::h6[contains(.,'Edited')]]", + createdListItem: "//li[contains(@class,'version-list-item') and child::div[not(contains(@class,'publish-action'))] and descendant::h6[contains(.,'Created')]]", + unpublishedListItem: "//li[contains(@class,'version-list-item') and child::div[contains(@class,'publish-action')] and descendant::h6[contains(.,'Unpublished')]]", + publishedListItem: "//li[contains(@class,'version-list-item') and child::div[contains(@class,'publish-action')] and descendant::h6[contains(.,'Published')]]", + sortedListItem: "//li[contains(@class,'version-list-item') and descendant::h6[contains(.,'Sorted')]]", + permissionsUpdatedListItem: "//li[contains(@class,'version-list-item') and descendant::h6[contains(.,'Permissions updated')]]", + markedAsReadyListItem: "//li[contains(@class,'version-list-item') and descendant::h6[contains(.,'Marked as Ready')]]", + movedListItem: "//li[contains(@class,'version-list-item') and descendant::h6[contains(.,'Moved')]]", + renamedListItem: "//li[contains(@class,'version-list-item') and descendant::h6[contains(.,'Renamed')]]", }; class BrowseVersionsWidget extends BaseVersionsWidget { @@ -17,11 +25,40 @@ class BrowseVersionsWidget extends BaseVersionsWidget { } get versionItems() { - return this.versionsWidget + XPATH.versionsList + XPATH.versionItem; + return this.versionsWidget + XPATH.versionsList + XPATH.versionsListItem; } get publishedItems() { - return this.versionsWidget + XPATH.versionsList + XPATH.publishedItems; + return this.versionsWidget + XPATH.versionsList + XPATH.publishedListItem; + } + + get unpublishedItems() { + return this.versionsWidget + XPATH.versionsList + XPATH.unpublishedListItem; + } + + //Gets items with headers - Sorted + get sortedItems() { + return this.versionsWidget + XPATH.versionsList + XPATH.sortedListItem; + } + + get editedItems() { + return this.versionsWidget + XPATH.versionsList + XPATH.editedListItem; + } + + get createdItems() { + return this.versionsWidget + XPATH.versionsList + XPATH.createdListItem; + } + + get permissionsUpdatedItems() { + return this.versionsWidget + XPATH.versionsList + XPATH.permissionsUpdatedListItem; + } + + get movedItems() { + return this.versionsWidget + XPATH.versionsList + XPATH.movedListItem; + } + + get renamedItems() { + return this.versionsWidget + XPATH.versionsList + XPATH.renamedListItem; } } diff --git a/testing/page_objects/browsepanel/detailspanel/content.widget.item.view.js b/testing/page_objects/browsepanel/detailspanel/content.widget.item.view.js index 108b5ee1..f6cfed66 100644 --- a/testing/page_objects/browsepanel/detailspanel/content.widget.item.view.js +++ b/testing/page_objects/browsepanel/detailspanel/content.widget.item.view.js @@ -45,7 +45,7 @@ class ContentWidgetItemView extends Page { async waitForWorkInProgressIconNotDisplayed() { try { - return await this.waitForElementNotDisplayed(xpath.container, appConst.workInProgressIcon); + return await this.waitForElementNotDisplayed(xpath.workInProgressIcon, appConst.mediumTimeout); } catch (err) { this.saveScreenshot("err_widget_item_workflow"); throw new Error("Workflow state should not be displayed in the widget item " + err); @@ -53,5 +53,3 @@ class ContentWidgetItemView extends Page { } } module.exports = ContentWidgetItemView; - - diff --git a/testing/page_objects/browsepanel/detailspanel/properties.widget.itemview.js b/testing/page_objects/browsepanel/detailspanel/properties.widget.itemview.js index 7f99aa79..fed83861 100644 --- a/testing/page_objects/browsepanel/detailspanel/properties.widget.itemview.js +++ b/testing/page_objects/browsepanel/detailspanel/properties.widget.itemview.js @@ -64,7 +64,7 @@ class PropertiesItemView extends Page { await this.clickOnElement(this.editSettingsButton); await this.pause(300); } catch (err) { - let screenshot = appConst.generateRandomName('prop_widget_edit'); + let screenshot = appConst.generateRandomName('err_prop_widget_edit'); await this.saveScreenshot(screenshot); throw new Error(`Properties Widget, Edit button is not displayed ${screenshot} ` + err); } diff --git a/testing/page_objects/browsepanel/new.content.dialog.js b/testing/page_objects/browsepanel/new.content.dialog.js index dec8d32d..ddbe900f 100644 --- a/testing/page_objects/browsepanel/new.content.dialog.js +++ b/testing/page_objects/browsepanel/new.content.dialog.js @@ -95,7 +95,7 @@ class NewContentDialog extends Page { async getItems() { let locator = XPATH.typesList + lib.H6_DISPLAY_NAME; - return this.getTextInElements(locator); + return await this.getTextInElements(locator); } } diff --git a/testing/page_objects/compare.content.versions.dialog.js b/testing/page_objects/compare.content.versions.dialog.js index ebda599d..6e580f4e 100644 --- a/testing/page_objects/compare.content.versions.dialog.js +++ b/testing/page_objects/compare.content.versions.dialog.js @@ -166,22 +166,10 @@ class CompareContentVersionsDialog extends Page { return await this.findElements(locator); } - async getArchivedOptionsInDropdownList() { - let locator = XPATH.containerLeft + XPATH.listItemNameAndIconView + "//div[contains(@class, 'icon-archive')]"; - await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - return await this.findElements(locator); - } - async clickOnRightDropdownHandle() { - try { - await this.waitForElementDisplayed(this.rightDropdownHandle, appConst.mediumTimeout); - await this.clickOnElement(this.rightDropdownHandle); - return await this.pause(300); - } catch (err) { - let screenshot = await this.saveScreenshotUniqueName('err_compare_right_dropdown'); - throw new Error("Compare Versions Dialog, error during clicking on Right Dropdown, screenshot: " + screenshot + ' ' + err); - } - + await this.waitForElementDisplayed(this.rightDropdownHandle, appConst.mediumTimeout); + await this.clickOnElement(this.rightDropdownHandle); + return await this.pause(300); } async getSortedOptionsInLeftDropdownList() { @@ -213,6 +201,24 @@ class CompareContentVersionsDialog extends Page { await this.waitForElementDisplayed(this.showEntireContentCheckbox, appConst.mediumTimeout); return await this.isSelected(checkBoxInput); } + + async getArchivedOptionsInDropdownList() { + let locator = XPATH.containerLeft + XPATH.listItemNameAndIconView + "//div[contains(@class, 'icon-archive')]"; + await this.waitForElementDisplayed(locator, appConst.mediumTimeout); + return await this.findElements(locator); + } + + async clickOnRightDropdownHandle() { + try { + await this.waitForElementDisplayed(this.rightDropdownHandle, appConst.mediumTimeout); + await this.clickOnElement(this.rightDropdownHandle); + return await this.pause(300); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_compare_right_dropdown'); + throw new Error("Compare Versions Dialog, error during clicking on Right Dropdown, screenshot: " + screenshot + ' ' + err); + } + + } } module.exports = CompareContentVersionsDialog; diff --git a/testing/page_objects/components/datetime.range.js b/testing/page_objects/components/datetime.range.js index 36644a87..33568827 100644 --- a/testing/page_objects/components/datetime.range.js +++ b/testing/page_objects/components/datetime.range.js @@ -7,108 +7,92 @@ const Page = require('../page'); const XPATH = { container: "//div[contains(@id,'DateTimeRange')]", onlineFromDateTime: "//div[contains(@id,'DateTimePicker') and preceding-sibling::label[text()='Online from']]//input[contains(@id,'TextInput')]", - onlineFromPickerPopup: "//div[contains(@id,'DateTimePicker') and preceding-sibling::label[text()='Online from']]" + - "//div[contains(@id,'DateTimePickerPopup')]", + onlineFromPickerPopup: "//div[contains(@id,'DateTimePicker') and preceding-sibling::label[text()='Online from']]//div[contains(@id,'DateTimePickerPopup')]", + onlineToPickerPopup: "//div[contains(@id,'DateTimePicker') and preceding-sibling::label[text()='Online to']]//div[contains(@id,'DateTimePickerPopup')]", onlineToDateTime: "//div[contains(@id,'DateTimePicker') and preceding-sibling::label[text()='Online to']]//input[contains(@id,'TextInput')]", validationRecording: `//div[contains(@id,'ValidationRecordingViewer')]//li`, }; -//ScheduleWizardStepForm, DateTimeRange +// ScheduleWizardStepForm, DateTimeRange form class DateTimeRange extends Page { + constructor(xpath) { + super(); + this.parentContainer = xpath === undefined ? '' : xpath; + } + get onlineFromDateTimeInput() { - return XPATH.container + XPATH.onlineFromDateTime; + return this.parentContainer + XPATH.container + XPATH.onlineFromDateTime; } get onlineToDateTimeInput() { - return XPATH.container + XPATH.onlineToDateTime; + return this.parentContainer + XPATH.container + XPATH.onlineToDateTime; } get validationRecord() { - return lib.FORM_VIEW + lib.OCCURRENCE_ERROR_BLOCK; + return this.parentContainer + lib.FORM_VIEW + lib.OCCURRENCE_ERROR_BLOCK; } - clearOnlineFrom(xpath) { - if (xpath === undefined) { - xpath = ''; - } - return this.clearTextInput(xpath + this.onlineFromDateTimeInput); + clearOnlineFrom() { + return this.clearTextInput(this.parentContainer + this.onlineFromDateTimeInput); } - typeOnlineFrom(value, xpath) { - if (xpath === undefined) { - xpath = ''; - } - return this.typeTextInInput(xpath + this.onlineFromDateTimeInput, value); + async showOnlineToPickerPopup() { + await this.clickOnElement(this.onlineToDateTimeInput); + return await this.pause(300); } - waitForOnlineToInputDisplayed(xpath) { - if (xpath === undefined) { - xpath = ''; - } - return this.waitForElementDisplayed(xpath + this.onlineToDateTimeInput, appConst.mediumTimeout); + async showOnlineFromPickerPopup() { + await this.clickOnElement(this.onlineFromDateTimeInput); + return await this.pause(300); } - waitForOnlineFromInputDisplayed(xpath) { - if (xpath === undefined) { - xpath = ''; - } - return this.waitForElementDisplayed(xpath + this.onlineFromDateTimeInput, appConst.mediumTimeout); + typeOnlineFrom(value) { + return this.typeTextInInput(this.onlineFromDateTimeInput, value); } - async getOnlineFrom(xpath) { - if (xpath === undefined) { - xpath = ''; - } + waitForOnlineToInputDisplayed() { + return this.waitForElementDisplayed(this.onlineToDateTimeInput, appConst.mediumTimeout); + } + + waitForOnlineFromInputDisplayed() { + return this.waitForElementDisplayed(this.onlineFromDateTimeInput, appConst.mediumTimeout); + } + + async getOnlineFrom() { await this.waitForOnlineFromInputDisplayed(); await this.pause(300); - return await this.getTextInInput(xpath + this.onlineFromDateTimeInput); + return await this.getTextInInput(this.onlineFromDateTimeInput); } - getOnlineTo(xpath) { - if (xpath === undefined) { - xpath = ''; - } + getOnlineTo() { return this.getTextInInput(this.onlineToDateTimeInput); } - typeOnlineTo(value, xpath) { - if (xpath === undefined) { - xpath = ''; - } + typeOnlineTo(value) { return this.typeTextInInput(this.onlineToDateTimeInput, value); } - waitForValidationRecording(ms, xpath) { - if (xpath === undefined) { - xpath = ''; - } - return this.waitForElementDisplayed(xpath + this.validationRecord, ms); + waitForValidationRecording(ms) { + return this.waitForElementDisplayed(this.validationRecord, ms); } - isValidationRecordingDisplayed(xpath) { - if (xpath === undefined) { - xpath = ''; - } - return this.isElementDisplayed(xpath + this.validationRecord); + isValidationRecordingDisplayed() { + return this.isElementDisplayed(this.validationRecord); } - getValidationRecord(xpath) { - if (xpath === undefined) { - xpath = ''; - } - return this.getText(xpath + this.validationRecord).catch(err => { - this.saveScreenshot('err_schedule_validation_record'); + async getValidationRecord() { + try { + return await this.getText(this.validationRecord); + } catch (err) { + await this.saveScreenshot('err_schedule_validation_record'); throw new Error('getting Validation text: ' + err); - }) + } } - waitForDisplayed(xpath) { - if (xpath === undefined) { - xpath = ''; - } - return this.waitUntilDisplayed(xpath + XPATH.container, appConst.shortTimeout); + waitForDisplayed() { + return this.waitUntilDisplayed(this.parentContainer + XPATH.container, appConst.shortTimeout); } async waitForOnlineFromPickerDisplayed() { @@ -119,16 +103,16 @@ class DateTimeRange extends Page { } } - waitForNotDisplayed(xpath) { - if (xpath === undefined) { - xpath = ''; + async waitForOnlineToPickerDisplayed() { + try { + return await this.waitUntilDisplayed(XPATH.onlineToPickerPopup, appConst.shortTimeout); + } catch (err) { + throw new Error("Online from picker popup should be opened!" + err); } - return this.waitUntilElementNotVisible(xpath + XPATH.container, appConst.shortTimeout); } - async doOpenOnlineFromPickerPopup() { - await this.clickOnElement(this.onlineFromDateTimeInput); - return await this.waitForOnlineFromPickerDisplayed(); + waitForNotDisplayed() { + return this.waitUntilElementNotVisible(this.parentContainer + XPATH.container, appConst.shortTimeout); } async clickOnHoursArrowOnlineFrom() { @@ -137,7 +121,6 @@ class DateTimeRange extends Page { await elems[0].click(); return await this.pause(300); } - } module.exports = DateTimeRange; diff --git a/testing/page_objects/components/htmlarea.js b/testing/page_objects/components/htmlarea.js index 6b887a5f..157a8659 100644 --- a/testing/page_objects/components/htmlarea.js +++ b/testing/page_objects/components/htmlarea.js @@ -6,38 +6,31 @@ const lib = require('../../libs/elements'); const appConst = require('../../libs/app_const'); const component = { - typeText: function (id, text) { + typeText(id, text) { return `CKEDITOR.instances['${id}'].setData('${text}')`; }, - getText: function (id) { + getText(id) { return `return CKEDITOR.instances['${id}'].getData()`; } }; class HtmlArea extends Page { - typeTextInHtmlArea(selector, text) { - return this.waitForElementDisplayed(selector, appConst.mediumTimeout).then(() => { - return this.getIdOfHtmlArea(selector + lib.TEXT_AREA); - }).then(id => { - this.execute(component.typeText(id, text)); - }); + + async typeTextInHtmlArea(selector, text) { + await this.waitForElementDisplayed(selector, appConst.mediumTimeout); + let id = await this.getIdOfHtmlArea(selector + lib.TEXT_AREA); + return await this.execute(component.typeText(id, text)); } getIdOfHtmlArea(selector) { return this.getAttribute(selector, 'id'); } - getTextFromHtmlArea(container) { - return this.waitForElementDisplayed(container + "//div[contains(@id,'cke_TextArea')]", - appConst.mediumTimeout).then(() => { - return this.getIdOfHtmlArea(container + lib.TEXT_AREA); - }).then(id => { - return this.execute(component.getText(id)); - }).then(response => { - let res = []; - res.push(response.trim()); - return res; - }) + async getTextFromHtmlArea(container) { + await this.waitForElementDisplayed(container + lib.CKE.TEXTAREA_DIV, appConst.mediumTimeout); + let id = await this.getIdOfHtmlArea(container + lib.TEXT_AREA); + let response = await this.execute(component.getText(id)); + return [].concat(response.trim()); } } diff --git a/testing/page_objects/components/projects/extended.principal.combobox.js b/testing/page_objects/components/projects/extended.principal.combobox.js index bf5f4936..2b7a8892 100644 --- a/testing/page_objects/components/projects/extended.principal.combobox.js +++ b/testing/page_objects/components/projects/extended.principal.combobox.js @@ -20,9 +20,9 @@ class ExtendedPrincipalComboBox extends BasDropdown { } // Custom - Selected users can read content - async clickOnFilteredByDisplayNameUserAndClickOnOk(displayName, parentElement) { + async clickOnFilteredByDisplayNameUserAndClickOnApply(displayName, parentElement) { try { - await this.clickOnFilteredItemAndClickOnOk(displayName, parentElement); + await this.clickOnFilteredByDisplayNameItemAndClickOnApply(displayName, parentElement); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_dropdown'); throw new Error('Error occurred in ProjectAccessControlComboBox, screenshot: ' + screenshot + ' ' + err); diff --git a/testing/page_objects/components/projects/project.access.control.combobox.js b/testing/page_objects/components/projects/project.access.control.combobox.js index 91430bc0..b150614a 100644 --- a/testing/page_objects/components/projects/project.access.control.combobox.js +++ b/testing/page_objects/components/projects/project.access.control.combobox.js @@ -19,9 +19,9 @@ class ProjectAccessControlComboBox extends BasDropdown { return XPATH.container; } - async clickOnFilteredByDisplayNamePrincipalAndClickOnOk(displayName, parentElement) { + async clickOnFilteredByDisplayNamePrincipalAndClickOnApply(displayName, parentElement) { try { - await this.clickOnFilteredItemAndClickOnOk(displayName, parentElement); + await this.clickOnFilteredByDisplayNameItemAndClickOnApply(displayName, parentElement); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_dropdown'); throw new Error('Error occurred in ProjectAccessControlComboBox, screenshot: ' + screenshot + ' ' + err); diff --git a/testing/page_objects/components/projects/project.applications.combobox.js b/testing/page_objects/components/projects/project.applications.combobox.js index 68126024..35801343 100644 --- a/testing/page_objects/components/projects/project.applications.combobox.js +++ b/testing/page_objects/components/projects/project.applications.combobox.js @@ -15,10 +15,10 @@ class ProjectApplicationsCombobox extends BasDropdown { async clickFilteredByAppNameItemAndClickOnOk(appDisplayName, parentElement) { try { - await this.clickOnFilteredItemAndClickOnOk(appDisplayName, parentElement); + await this.clickOnFilteredByDisplayNameItemAndClickOnApply(appDisplayName, parentElement); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_dropdown'); - throw new Error('Error occurred in Project Applications Comboboox selector, screenshot: ' + screenshot + ' ' + err); + throw new Error(`Error occurred in Project Applications Comboboox selector, screenshot:${screenshot} ` + err); } } } diff --git a/testing/page_objects/components/projects/projects.combobox.js b/testing/page_objects/components/projects/projects.combobox.js index 6df3509b..f7374d26 100644 --- a/testing/page_objects/components/projects/projects.combobox.js +++ b/testing/page_objects/components/projects/projects.combobox.js @@ -13,21 +13,30 @@ class ProjectsSelector extends BasDropdown { return XPATH.container; } - async selectFilteredByIdAndClickOnOk(projectId, parentElement) { + async selectFilteredByIdAndClickOnApply(projectId, parentElement) { try { - await this.clickOnFilteredByNameItemAndClickOnOk(projectId, parentElement); + await this.clickOnFilteredByNameItemAndClickOnApply(projectId, parentElement); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_dropdown'); throw new Error('Error occurred in Projects Selector selector, screenshot: ' + screenshot + ' ' + err); } } - async selectFilteredByDisplayNameAndClickOnOk(displayName, parentElement) { + async selectFilteredByDisplayNameAndClickOnApply(displayName, parentElement) { try { - await this.clickOnFilteredItemAndClickOnOk(displayName, parentElement); + await this.clickOnFilteredByDisplayNameItemAndClickOnApply(displayName, parentElement); } catch (err) { - let screenshot = await this.saveScreenshotUniqueName('err_dropdown'); - throw new Error('Error occurred in Project Selector selector, screenshot: ' + screenshot + ' ' + err); + let screenshot = await this.saveScreenshotUniqueName('err_project_selector_dropdown'); + throw new Error(`Error occurred in Project Selector selector, screenshot:${screenshot} ` + err); + } + } + + async selectFilteredByDisplayName(displayName, parentElement) { + try { + await this.clickOnFilteredByDisplayNameItem(displayName, parentElement); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_project_selector_dropdown'); + throw new Error(`Error occurred in Project Selector selector, screenshot:${screenshot} ` + err); } } } diff --git a/testing/page_objects/components/selectors/base.dropdown.js b/testing/page_objects/components/selectors/base.dropdown.js index efe24b29..397ec0b6 100644 --- a/testing/page_objects/components/selectors/base.dropdown.js +++ b/testing/page_objects/components/selectors/base.dropdown.js @@ -4,9 +4,14 @@ const lib = require('../../../libs/elements'); const appConst = require('../../../libs/app_const'); const Page = require('../../page'); + const XPATH = { rightCheckBoxDiv: "//li[contains(@class,'checkbox-right')]//div[contains(@id,'Checkbox')]", rightCheckboxByDisplayName: displayName => `//li[contains(@class,'checkbox-right') and descendant::h6[contains(@class,'main-name') and text()='${displayName}']]//div[contains(@id,'Checkbox')]`, + expanderIconByName: name => { + return `//div[contains(@id,'NamesView') and child::p[contains(@class,'sub-name') and contains(.,'${name}')]]` + + `//ancestor::li[contains(@id,'ContentListElement')]//div[contains(@class,'toggle icon-arrow_drop_up')]`; + }, } class BaseDropdown extends Page { @@ -62,7 +67,7 @@ class BaseDropdown extends Page { if (parentLocator === undefined) { parentLocator = ''; } - await this.waitUntilDisplayed(parentLocator + this.applySelectionButton, appConst.mediumTimeout); + await this.waitUntilDisplayed(parentLocator + this.applySelectionButton, appConst.shortTimeout); await this.pause(200); } @@ -86,6 +91,13 @@ class BaseDropdown extends Page { return await this.pause(300); } + async clickOnExpanderIconInOptionsList(listItemName) { + let locator = XPATH.expanderIconByName(listItemName); + await this.waitForElementDisplayed(locator, appConst.mediumTimeout); + await this.clickOnElement(locator); + return await this.pause(300); + } + async isOptionsFilterInputDisplayed(parentLocator) { if (parentLocator === undefined) { parentLocator = ''; @@ -99,17 +111,24 @@ class BaseDropdown extends Page { // 1. Insert a text in Filter input // 2. Click on the filtered by displayName item (h6[contains(@class,'main-name')) - // 3. Click on OK button and apply the selection. - async clickOnFilteredItemAndClickOnOk(optionDisplayName, parentLocator) { + // 3. Click on Apply button and apply the selection. + async clickOnFilteredByDisplayNameItemAndClickOnApply(optionDisplayName, parentLocator) { + // 1. Click on the filtered item: + await this.clickOnFilteredByDisplayNameItem(optionDisplayName, parentLocator); + // 3. Click on 'OK' button: + return await this.clickOnApplySelectionButton(parentLocator); + } + + // Do filter by a display name then Click on the item + async clickOnFilteredByDisplayNameItem(optionDisplayName, parentLocator) { // parentLocator - modal dialog or wizard panel // 1. Insert the text in Options Filter Input: await this.filterItem(optionDisplayName, parentLocator); // 2. Wait for the required option is displayed then click on it: await this.clickOnOptionByDisplayName(optionDisplayName, parentLocator); - // 3. Click on 'OK' button: - return await this.clickOnApplySelectionButton(parentLocator); } + // Click on option-item by display name: async clickOnOptionByDisplayName(optionDisplayName, parentLocator) { let optionLocator = this.buildLocatorForOptionByDisplayName(optionDisplayName, parentLocator); // Wait for the required option is displayed: @@ -121,7 +140,7 @@ class BaseDropdown extends Page { // 1. Insert a text in Filter input // 2. Click on the filtered by name item (p[contains(@class,'sub-name')) // 3. Click on OK button and apply the selection. - async clickOnFilteredByNameItemAndClickOnOk(optionName, parentLocator) { + async clickOnFilteredByNameItemAndClickOnApply(optionName, parentLocator) { // parent locator - it is locator for parent modal dialog or wizard form, // 1. type the text in Options Filter Input: await this.filterItem(optionName, parentLocator); @@ -131,6 +150,14 @@ class BaseDropdown extends Page { return await this.clickOnApplySelectionButton(parentLocator); } + async clickOnFilteredByNameItem(optionName, parentLocator) { + // parent locator - it is locator for parent modal dialog or wizard form, + // 1. type the text in Options Filter Input: + await this.filterItem(optionName, parentLocator); + // 3. Click on the row with the item: + await this.clickOnOptionByName(optionName, parentLocator); + } + async clickOnOptionByName(name, parentLocator) { let optionLocator = this.buildLocatorForOptionByName(name, parentLocator); // Wait for the required option is displayed: @@ -185,7 +212,6 @@ class BaseDropdown extends Page { //return attr.includes('active') ? 'tree' : 'flat'; return attr.includes('folder-closed') ? 'flat' : 'tree'; } - } module.exports = BaseDropdown; diff --git a/testing/page_objects/components/selectors/compare.versions.dropdown.js b/testing/page_objects/components/selectors/compare.versions.dropdown.js index ea6d2aac..a52d2b2e 100644 --- a/testing/page_objects/components/selectors/compare.versions.dropdown.js +++ b/testing/page_objects/components/selectors/compare.versions.dropdown.js @@ -16,9 +16,9 @@ class CompareDropdown extends BaseDropdown { return XPATH.container; } - async selectFilteredVersionItemAndClickOnOk(optionName, parentElement) { + async selectFilteredVersionItem(optionName, parentElement) { try { - await this.clickOnFilteredItemAndClickOnOk(optionName, parentElement); + await this.clickOnFilteredByNameItemAndClickOnApply(optionName, parentElement); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_dropdown'); throw new Error('CompareDropdown - Error during selecting the option, screenshot: ' + screenshot + ' ' + err); diff --git a/testing/page_objects/components/selectors/custom.selector.combobox.js b/testing/page_objects/components/selectors/custom.selector.combobox.js deleted file mode 100644 index f1124b30..00000000 --- a/testing/page_objects/components/selectors/custom.selector.combobox.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Created on 20.02.2024 - */ -const BaseDropdown = require('./base.dropdown'); -const lib = require('../../../libs/elements'); -const appConst = require('../../../libs/app_const'); - -const XPATH = { - container: "//div[contains(@id,'CustomSelectorComboBox')]", - selectorListBoxUL: "//ul[contains(@id,'CustomSelectorListBox')]", - optionByText: text => { - return `//div[contains(@id,'ComboBoxDisplayValueViewer') and text()='${text}']` - }, -}; - -class CustomSelectorComboBox extends BaseDropdown { - - get container() { - return XPATH.container; - } - - async selectFilteredOptionAndClickOnOk(optionName, parentElement) { - try { - await this.clickOnFilteredItemAndClickOnOk(optionName, parentElement); - } catch (err) { - let screenshot = await this.saveScreenshotUniqueName('err_dropdown'); - throw new Error('CustomSelectorComboBox - Error during selecting the option, screenshot: ' + screenshot + ' ' + err); - } - } - - async getOptionsName(parentXpath) { - if (parentXpath === undefined) { - parentXpath = ''; - } - let locator = parentXpath + XPATH.selectorListBoxUL + lib.DROPDOWN_SELECTOR.DROPDOWN_LIST_ITEM + lib.H6_DISPLAY_NAME; - await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - await this.pause(500); - return await this.getTextInDisplayedElements(locator); - } -} - -module.exports = CustomSelectorComboBox; diff --git a/testing/page_objects/components/selectors/fragment.dropdown.js b/testing/page_objects/components/selectors/fragment.dropdown.js deleted file mode 100644 index 534fde0b..00000000 --- a/testing/page_objects/components/selectors/fragment.dropdown.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Created on 01.03.2024 - */ -const BaseDropdown = require('./base.dropdown'); -const lib = require('../../../libs/elements'); -const appConst = require('../../../libs/app_const'); - -const XPATH = { - container: "//div[contains(@id,'FragmentDropdown')]", - fragmentDropdownListUL: "//ul[contains(@id,'FragmentDropdownList')]", -} - -class FragmentDropdown extends BaseDropdown { - - get container() { - return XPATH.container; - } - - async selectFilteredFragmentAndClickOnOk(optionName, parentElement) { - try { - await this.clickOnFilteredItemAndClickOnOk(optionName, parentElement); - } catch (err) { - let screenshot = await this.saveScreenshotUniqueName('err_dropdown'); - throw new Error('CustomSelectorComboBox - Error during selecting the option, screenshot: ' + screenshot + ' ' + err); - } - } - - async getOptionsDisplayName() { - let locator = XPATH.container + XPATH.fragmentDropdownListUL + lib.DROPDOWN_SELECTOR.DROPDOWN_LIST_ITEM + lib.H6_DISPLAY_NAME; - await this.waitUntilDisplayed(locator, appConst.mediumTimeout); - await this.pause(300); - return await this.getTextInDisplayedElements(locator); - } - - async getSelectedOptionPath(optionName) { - let locator = XPATH.container + lib.P_SUB_NAME; - return await this.getText(locator); - } -} - -module.exports = FragmentDropdown; diff --git a/testing/page_objects/components/selectors/image.selector.dropdown.js b/testing/page_objects/components/selectors/image.selector.dropdown.js index c6e58d05..ba40215b 100644 --- a/testing/page_objects/components/selectors/image.selector.dropdown.js +++ b/testing/page_objects/components/selectors/image.selector.dropdown.js @@ -12,10 +12,6 @@ const XPATH = { return `//div[contains(@id,'NamesView') and child::p[contains(@class,'sub-name') and contains(.,'${name}')]]` + `//ancestor::li[contains(@id,'ContentListElement')]//div[contains(@class,'toggle icon-arrow_drop_up')]`; }, - expanderIconByDisplayName: displayName => { - return `//div[contains(@id,'NamesView') and child::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]` + - `//ancestor::li[contains(@id,'ContentListElement')]/div[contains(@class,'toggle icon-arrow_drop_up')]`; - }, imageByDisplayNameInTreeMode: displayName => { return lib.DROPDOWN_SELECTOR.CONTENTS_TREE_LIST_UL + lib.DROPDOWN_SELECTOR.OPTIONS_LI_ELEMENT + `//h6[contains(@class,'main-name') and contains(text(),'${displayName}')]`; @@ -35,10 +31,10 @@ class ImageSelectorDropdown extends BaseDropdown { async selectFilteredImageInFlatMode(imageDisplayName, parentLocator) { try { // parentLocator = modal dialog or wizard panel... - await this.clickOnFilteredItemAndClickOnOk(imageDisplayName, parentLocator); + await this.clickOnFilteredByDisplayNameItem(imageDisplayName, parentLocator); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_img_selector_flat'); - throw new Error('Image selector - Error during selecting the option, screenshot: ' + screenshot + ' ' + err); + throw new Error(`Image selector - Error during selecting the option, screenshot: ${screenshot} ` + err); } } @@ -66,12 +62,6 @@ class ImageSelectorDropdown extends BaseDropdown { await this.clickOnElement(locator); } - async clickOnOptionExpanderIcon(optionDisplayName) { - let locator = XPATH.expanderIconByName(optionDisplayName); - await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - await this.clickOnElement(locator); - return await this.pause(300); - } // Gets all content-statuses in the expanded dropdown list async getImagesStatusInOptions() { diff --git a/testing/page_objects/components/selectors/inspect.panel.controller.selector.js b/testing/page_objects/components/selectors/inspect.panel.controller.selector.js index 99f0777c..9e970f33 100644 --- a/testing/page_objects/components/selectors/inspect.panel.controller.selector.js +++ b/testing/page_objects/components/selectors/inspect.panel.controller.selector.js @@ -19,9 +19,9 @@ class InspectPanelControllerSelector extends BaseDropdown { return XPATH.container; } - async selectFilteredOptionAndClickOnOk(optionName, parentElement) { + async selectFilteredOptionByDisplayName(optionName, parentElement) { try { - await this.clickOnFilteredItemAndClickOnOk(optionName, parentElement); + await this.clickOnFilteredByDisplayNameItem(optionName, parentElement); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_dropdown'); throw new Error('CustomSelectorComboBox - Error during selecting the option, screenshot: ' + screenshot + ' ' + err); diff --git a/testing/page_objects/components/selectors/locale.selector.dropdown.js b/testing/page_objects/components/selectors/locale.selector.dropdown.js index 0fb3bc17..da54e227 100644 --- a/testing/page_objects/components/selectors/locale.selector.dropdown.js +++ b/testing/page_objects/components/selectors/locale.selector.dropdown.js @@ -12,12 +12,12 @@ class LocaleSelectorDropdown extends BasDropdown { return XPATH.container; } - async clickOnFilteredLanguageAndClickOnOk(language) { + async clickOnFilteredLanguage(language, parentLocator) { try { - await this.clickOnFilteredItemAndClickOnOk(language); + await this.clickOnFilteredByDisplayNameItem(language, parentLocator); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_dropdown'); - throw new Error('Content selector - Error during selecting the option, screenshot: ' + screenshot + ' ' + err); + throw new Error(`Content selector - Error during selecting the option, screenshot: ${screenshot}` + err); } } } diff --git a/testing/page_objects/components/selectors/page.descriptor.dropdown.js b/testing/page_objects/components/selectors/page.descriptor.dropdown.js index 8aec7efa..b5b2ffb5 100644 --- a/testing/page_objects/components/selectors/page.descriptor.dropdown.js +++ b/testing/page_objects/components/selectors/page.descriptor.dropdown.js @@ -16,10 +16,10 @@ class PageDescriptorDropdown extends BaseDropdown { async selectFilteredControllerAndClickOnOk(controllerDisplayName) { try { - await this.clickOnFilteredItemAndClickOnOk(controllerDisplayName); + await this.clickOnFilteredByDisplayNameItem(controllerDisplayName); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_dropdown'); - throw new Error('Page descriptor selector - Error during selecting the option, screenshot: ' + screenshot + ' ' + err); + throw new Error(`Page descriptor selector - Error during selecting the option, screenshot: ${screenshot} ` + err); } } } diff --git a/testing/page_objects/components/selectors/principal.combobox.dropdown.js b/testing/page_objects/components/selectors/principal.combobox.dropdown.js new file mode 100644 index 00000000..6c47961d --- /dev/null +++ b/testing/page_objects/components/selectors/principal.combobox.dropdown.js @@ -0,0 +1,39 @@ +/** + * Created on 12.02.2024 + */ +const BasDropdown = require('./base.dropdown'); +const lib = require('../../../libs/elements'); +const appConst = require('../../../libs/app_const'); +const XPATH = { + container: "//div[contains(@id,'CSPrincipalCombobox')]", + listBoxUL: "//ul[contains(@id,'PrincipalsListBox')]", + principalViewerDiv: "//div[contains(@id,'PrincipalViewer')]", +}; + +class PrincipalComboBox extends BasDropdown { + + get container() { + return XPATH.container; + } + + async selectFilteredUser(userDisplayName, parentElement) { + try { + await this.clickOnFilteredByDisplayNameItem(userDisplayName, parentElement); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_dropdown'); + throw new Error('Principal Comboboox selector - Error during selecting the option, screenshot: ' + screenshot + ' ' + err); + } + } + + async getPrincipalsDisplayNameInOptions(parentXpath) { + if (parentXpath === undefined) { + parentXpath = ''; + } + let locator = parentXpath + XPATH.listBoxUL + XPATH.principalViewerDiv + lib.H6_DISPLAY_NAME; + await this.waitForElementDisplayed(locator, appConst.mediumTimeout); + await this.pause(500); + return await this.getTextInDisplayedElements(locator); + } +} + +module.exports = PrincipalComboBox; diff --git a/testing/page_objects/components/selectors/widget.selector.dropdown.js b/testing/page_objects/components/selectors/widget.selector.dropdown.js index 4b6a8189..fc235268 100644 --- a/testing/page_objects/components/selectors/widget.selector.dropdown.js +++ b/testing/page_objects/components/selectors/widget.selector.dropdown.js @@ -16,9 +16,9 @@ class WidgetSelectorDropdown extends BaseDropdown { return XPATH.container; } - async selectFilteredWidgetItemAndClickOnOk(widgetName, parentElement) { + async selectFilteredWidgetItem(widgetDisplayName, parentElement) { try { - await this.clickOnFilteredItemAndClickOnOk(widgetName, parentElement); + await this.clickOnFilteredByDisplayNameItem(widgetDisplayName, parentElement); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_dropdown'); throw new Error('WidgetSelectorDropdown - Error during selecting the option, screenshot: ' + screenshot + ' ' + err); diff --git a/testing/page_objects/components/text.component.js b/testing/page_objects/components/text.component.js deleted file mode 100644 index 3729dbee..00000000 --- a/testing/page_objects/components/text.component.js +++ /dev/null @@ -1,183 +0,0 @@ -/** - * Created on 10.05.2018. - */ -const Page = require('../page'); -const lib = require('../../libs/elements'); -const appConst = require('../../libs/app_const'); -const utils = require('../../libs/studio.utils'); -const InsertLinkDialog = require('../../page_objects/wizardpanel/insert.link.modal.dialog.cke'); -const InsertAnchorDialog = require('../../page_objects/wizardpanel/insert.anchor.dialog.cke'); -const InsertImageDialog = require('../../page_objects/wizardpanel/insert.image.dialog.cke'); - -const component = { - toolbox: `//span[contains(@class,'cke_toolbox')]`, -}; - -class TextComponent extends Page { - - get insertTableButton() { - return component.toolbox + lib.CKE.insertTableButton; - } - - get insertLinkButton() { - return component.toolbox + lib.CKE.insertLinkButton; - } - - get insertAnchorButton() { - return component.toolbox + lib.CKE.insertAnchorButton; - } - - get insertImageButton() { - return component.toolbox + lib.CKE.insertImageButton; - } - - get boldButton() { - return component.toolbox + lib.CKE.boldButton; - } - - get italicButton() { - return component.toolbox + lib.CKE.italicButton; - } - - get underlineButton() { - return component.toolbox + lib.CKE.underlineButton; - } - - get justifyButton() { - return component.toolbox + lib.CKE.justifyButton; - } - - get alignLeftButton() { - return component.toolbox + lib.CKE.alignLeftButton; - } - - get alignRightButton() { - return component.toolbox + lib.CKE.alignRightButton; - } - - get centerButton() { - return component.toolbox + lib.CKE.centerButton; - } - - get decreaseIndentButton() { - return component.toolbox + lib.CKE.decreaseIndentButton; - } - - get increaseIndentButton() { - return component.toolbox + lib.CKE.increaseIndentButton; - } - - get bulletedButton() { - return component.toolbox + lib.CKE.bulletedButton; - } - - get insertSpecialCharacterButton() { - return component.toolbox + lib.CKE.insertSpecialCharacter; - } - - async typeTextInCkeEditor(text) { - await this.switchToLiveEditFrame(); - await this.waitForElementDisplayed(lib.RICH_TEXT_EDITOR, appConst.mediumTimeout); - let id = await this.getEditorId(); - await utils.setTextInCKE(id, text); - await this.getBrowser().switchToParentFrame(); - return await this.pause(1000); - } - - async getTextFromEditor() { - await this.waitForElementDisplayed(lib.RICH_TEXT_EDITOR, appConst.mediumTimeout); - let editorId = await this.getEditorId(); - let result = await utils.getTextInCKE(editorId); - return result.trim(); - } - - getEditorId() { - return this.getAttribute(lib.RICH_TEXT_EDITOR, 'id'); - } - - switchToLiveEditFrame() { - return this.switchToFrame(lib.LIVE_EDIT_FRAME); - } - - async switchToCKETableFrameAndInsertTable() { - await this.waitForElementDisplayed("//iframe[contains(@class,'cke_panel_frame')]", appConst.mediumTimeout); - await this.switchToFrame("//iframe[contains(@class,'cke_panel_frame')]"); - await this.clickOnElement("//div[contains(@class,'cke_panel_block')]"); - return await this.getBrowser().switchToParentFrame(); - } - - async waitForTableDisplayedInCke() { - await this.waitForElementDisplayed("//iframe[contains(@class,'cke_panel_frame')]", appConst.mediumTimeout); - await this.switchToFrame("//iframe[contains(@class,'cke_panel_frame')]"); - let table = "//table"; - let result = await this.waitForElementDisplayed(table, appConst.shortTimeout); - await this.getBrowser().switchToParentFrame(); - return result; - } - - async clickOnInsertTableButton() { - console.log('Insert Table dialog'); - await this.waitForElementDisplayed(lib.RICH_TEXT_EDITOR, appConst.mediumTimeout); - return await this.clickOnElement(this.insertTableButton); - } - - async clickOnInsertLinkButton() { - let insertLinkDialog = new InsertLinkDialog(); - try { - await this.waitForElementDisplayed(lib.RICH_TEXT_EDITOR, appConst.mediumTimeout); - await this.clickOnElement(this.insertLinkButton); - await this.switchToParentFrame(); - return await insertLinkDialog.waitForDialogLoaded(); - } catch (err) { - this.saveScreenshot('err_insert_link_cke'); - throw new Error('Text Component - Error when clicking on Insert Link button'); - } - } - - async clickOnInsertAnchorButton() { - let insertAnchorDialog = new InsertAnchorDialog(); - await this.waitForElementDisplayed(lib.RICH_TEXT_EDITOR, appConst.mediumTimeout); - await this.clickOnElement(this.insertAnchorButton); - await this.switchToParentFrame(); - return await insertAnchorDialog.waitForDialogLoaded(); - } - - async clickOnInsertImageButton() { - let insertImageDialog = new InsertImageDialog(); - await this.waitForElementDisplayed(lib.RICH_TEXT_EDITOR, appConst.mediumTimeout); - await this.clickOnElement(this.insertImageButton); - await this.switchToParentFrame(); - return await insertImageDialog.waitForDialogVisible(); - } - - async waitForBoldButtonDisplayed() { - await this.getBrowser().waitUntil(async () => { - let result = await this.getDisplayedElements(this.boldButton); - return result.length > 0; - }, {timeout: appConst.mediumTimeout, timeoutMsg: "Bold button should be displayed"}); - } - - async waitForItalicButtonDisplayed() { - await this.getBrowser().waitUntil(async () => { - let result = await this.getDisplayedElements(this.italicButton); - return result.length > 0; - }, {timeout: appConst.mediumTimeout, timeoutMsg: "Italic button should be displayed"}); - } - - waitForBulletedButtonDisplayed() { - return this.waitForElementDisplayed(this.bulletedButton, appConst.mediumTimeout); - } - - async waitForUnderlineButtonDisplayed() { - await this.getBrowser().waitUntil(async () => { - let result = await this.getDisplayedElements(this.underlineButton); - return result.length > 0; - }, {timeout: appConst.mediumTimeout, timeoutMsg: "Underline button should be displayed"}); - } - - waitForJustifyButtonButtonDisplayed() { - return this.waitForElementDisplayed(this.justifyButton, appConst.mediumTimeout); - } -} - -module.exports = TextComponent; diff --git a/testing/page_objects/confirm.content.delete.dialog.js b/testing/page_objects/confirm.content.delete.dialog.js index c8803e37..29c1c6e6 100644 --- a/testing/page_objects/confirm.content.delete.dialog.js +++ b/testing/page_objects/confirm.content.delete.dialog.js @@ -43,7 +43,7 @@ class ConfirmValueDialog extends Page { await this.waitForElementDisplayed(XPATH.container, appConst.mediumTimeout); await this.pause(300); } catch (err) { - let screenshot = await this.saveScreenshot('err_confirm_delete'); + let screenshot = await this.saveScreenshotUniqueName('err_confirm_delete'); throw new Error("Confirm Value Dialog was not loaded, screenshot: " + screenshot + ' ' + err); } } @@ -52,7 +52,7 @@ class ConfirmValueDialog extends Page { try { return this.waitForElementNotDisplayed(XPATH.container, appConst.mediumTimeout) } catch (err) { - let screenshot = await this.saveScreenshot('err_confirm_value_dlg'); + let screenshot = await this.saveScreenshotUniqueName('err_confirm_value_dlg'); throw new Error("Confirm Value Dialog must be closed, screenshot: " + screenshot + ' ' + err); } } @@ -61,7 +61,7 @@ class ConfirmValueDialog extends Page { try { await this.waitForElementDisabled(this.confirmButton, appConst.mediumTimeout) } catch (err) { - let screenshot = await this.saveScreenshot('err_confirm_value_dlg'); + let screenshot = await this.saveScreenshotUniqueName('err_confirm_value_dlg'); throw new Error("Confirm Value Dialog - Confirm button is not disabled, screenshot: " + screenshot + ' ' + err); } } @@ -70,7 +70,7 @@ class ConfirmValueDialog extends Page { try { await this.waitForElementEnabled(this.confirmButton, appConst.mediumTimeout) } catch (err) { - let screenshot = await this.saveScreenshot('err_confirm_value_dlg'); + let screenshot = await this.saveScreenshotUniqueName('err_confirm_value_dlg'); throw new Error("Confirm Value Dialog - Confirm button should be enabled, screenshot " + screenshot + ' ' + err); } } @@ -101,7 +101,7 @@ class ConfirmValueDialog extends Page { await this.waitForElementNotDisplayed(XPATH.container, appConst.mediumTimeout); return await this.pause(1000); } catch (err) { - await this.saveScreenshot('err_confirmation_dialog'); + await this.saveScreenshotUniqueName('err_confirmation_dialog'); throw new Error('Confirm Value dialog - Error during clicking on Confirm button.' + err); } } diff --git a/testing/page_objects/confirmation.mask.js b/testing/page_objects/confirmation.mask.js index 8a2a3784..965d33ab 100644 --- a/testing/page_objects/confirmation.mask.js +++ b/testing/page_objects/confirmation.mask.js @@ -13,8 +13,6 @@ const XPATH = { class ConfirmationMask extends Page { - - get cancelButton() { return XPATH.container + XPATH.cancelButton; } diff --git a/testing/page_objects/content.publish.dialog.js b/testing/page_objects/content.publish.dialog.js index befa1f69..cddd625b 100644 --- a/testing/page_objects/content.publish.dialog.js +++ b/testing/page_objects/content.publish.dialog.js @@ -490,8 +490,13 @@ class ContentPublishDialog extends Page { } async clickOnOkInPickerPopup() { - let dateTimePickerPopup = new DateTimePickerPopup(); - await dateTimePickerPopup.clickOnOkButton(); + try { + let dateTimePickerPopup = new DateTimePickerPopup(); + await dateTimePickerPopup.clickOnOkButton(); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_picker_popup'); + throw new Error(`Error occurred in picker popup dialog, screenshot: ${screenshot} ` + err); + } } async getNumberItemsToPublish() { diff --git a/testing/page_objects/delete.content.dialog.js b/testing/page_objects/delete.content.dialog.js index 0b37063d..50e104ec 100644 --- a/testing/page_objects/delete.content.dialog.js +++ b/testing/page_objects/delete.content.dialog.js @@ -3,30 +3,35 @@ const appConst = require('../libs/app_const'); const lib = require('../libs/elements'); const XPATH = { container: `//div[contains(@id,'ContentDeleteDialog')]`, + inboundErrorStateEntry: "//div[contains(@id,'DialogStateEntry')]/span[text()='Inbound references']", archiveOrDeleteMenu: `//div[contains(@id,'MenuButton')]`, - archiveButton: `//button/span[contains(.,'Archive')]`, deleteMenuItem: `//li[contains(@id,'MenuItem') and contains(.,'Delete')]`, cancelButton: `//button/span[text()='Cancel']`, - itemToDeleteList: `//ul[contains(@id,'DeleteDialogItemList')]`, + itemToDeleteList: `//ul[contains(@id,'DialogWithRefsItemList')]`, itemViewer: `//div[contains(@id,'DeleteItemViewer']`, - inboundWarningPart2: "//h6/span[contains(@class,'part2')]", - dependantList: "//ul[contains(@id,'DeleteDialogDependantList')]", - hideDependantItemsLink: "//div[@class='dependants']//h6[@class='dependants-header' and contains(.,'Hide dependent items')]", - showDependantItemsLink: "//div[@class='dependants']//h6[@class='dependants-header' and contains(.,'Show dependent items')]", + dependantListUl: "//ul[contains(@id,'DialogWithRefsDependantList')]", + dependantsHeader: "//div[@class='dependants-header']/span[@class='dependants-title']", itemToDeleteByDisplayName: displayName => { return `//div[contains(@id,'NamesAndIconView') and descendant::span[contains(@class,'display-name') and contains(.,'${displayName}')]]` }, inboundLink: `//a[contains(@class,'inbound-dependency')]`, getContentStatus(displayName) { - return `//div[contains(@id,'StatusSelectionItem') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]//div[contains(@class,'status')][2]` + return `//div[contains(@id,'ArchiveSelectableItem') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]/div[contains(@class,'status')][2]`; + }, + showReferencesButton(displayName) { + return `//div[contains(@id,'ArchiveSelectableItem') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]/button[contains(@id,'ActionButton') and child::span[text()='Show references']]`; } }; // it appears when select a content and click on 'Delete' button on the toolbar class DeleteContentDialog extends Page { + get dependentsHeader() { + return XPATH.container + XPATH.dependantsHeader; + } + get cancelButton() { - return XPATH.container + XPATH.cancelButton; + return XPATH.container + lib.dialogButton('Cancel'); } get cancelTopButton() { @@ -34,7 +39,7 @@ class DeleteContentDialog extends Page { } get archiveButton() { - return XPATH.container + XPATH.archiveOrDeleteMenu + XPATH.archiveButton; + return XPATH.container + XPATH.archiveOrDeleteMenu + lib.actionButton('Archive'); } get archiveMenuDropDownHandle() { @@ -49,10 +54,14 @@ class DeleteContentDialog extends Page { return XPATH.container + XPATH.showDependantItemsLink; } + get ignoreInboundReferencesButton() { + return XPATH.container + lib.actionButton('Ignore inbound references'); + } + async waitForDialogOpened() { try { await this.waitForElementDisplayed(this.archiveButton, appConst.mediumTimeout); - return await this.pause(300); + return await this.pause(500); } catch (err) { await this.saveScreenshot(appConst.generateRandomName('err_archive_dialog')); throw new Error('Archive or delete dialog is not loaded ' + err) @@ -62,7 +71,7 @@ class DeleteContentDialog extends Page { waitForDialogClosed() { return this.waitForElementNotDisplayed(XPATH.container, appConst.mediumTimeout).catch(err => { this.saveScreenshot('err_close_delete_content_dialog'); - throw new Error('Delete content dialog must be closed'); + throw new Error('Delete content dialog must be closed ' + err); }) } @@ -74,15 +83,16 @@ class DeleteContentDialog extends Page { return await this.clickOnElement(this.cancelTopButton); } - //Clicks on 'Archive' button.(Confirm Archive dialog can appear) + // Clicks on 'Archive' button.(Confirm Archive dialog can appear) async clickOnArchiveButton() { try { await this.waitForElementDisplayed(this.archiveButton, appConst.mediumTimeout); + await this.waitForElementEnabled(this.archiveButton, appConst.mediumTimeout); await this.clickOnElement(this.archiveButton); return await this.pause(500); } catch (err) { - await this.saveScreenshot('err_click_on_delete_dialog'); - throw new Error(err); + let screenshot = await this.saveScreenshotUniqueName('err_click_on_delete_dialog'); + throw new Error("Delete Content Dialog, Archive button, screenshot:" + screenshot + ' ' + err); } } @@ -91,23 +101,24 @@ class DeleteContentDialog extends Page { let menuItem = XPATH.container + XPATH.archiveOrDeleteMenu + XPATH.deleteMenuItem; await this.waitForElementDisplayed(menuItem, appConst.mediumTimeout); await this.clickOnElement(menuItem); - return await this.pause(300); + return await this.pause(500); } - //Call the method for deleting single content, Delete Content should be closed after clicking on the menu item + // Call the method for deleting single content, Delete Content should be closed after clicking on the menu item async clickOnDeleteMenuItemAndWaitForClosed() { try { await this.clickOnDeleteMenuItem(); return await this.waitForDialogClosed(); } catch (err) { - await this.saveScreenshot('err_click_on_delete_dialog'); - throw new Error(err); + let screenshot = await this.saveScreenshotUniqueName('err_click_on_delete_dialog'); + throw new Error("Delete Content Dialog, Delete menu item, screenshot:" + screenshot + ' ' + err); } } //Expands the menu in 'Archive' button async clickOnArchiveMenuDropDownHandle() { await this.waitForArchiveMenuDropDownHandleDisplayed(); + await this.waitForArchiveMenuDropDownHandleEnabled(); await this.clickOnElement(this.archiveMenuDropDownHandle); return await this.pause(300); } @@ -116,17 +127,21 @@ class DeleteContentDialog extends Page { return this.waitForElementDisplayed(this.archiveMenuDropDownHandle, appConst.mediumTimeout); } - getInboundDependenciesWarning() { - let selector = XPATH.container + XPATH.inboundWarningPart2; - return this.getText(selector); + waitForArchiveMenuDropDownHandleEnabled() { + return this.waitForElementEnabled(this.archiveMenuDropDownHandle, appConst.mediumTimeout); } - async clickOnShowInboundLink(itemDisplayName) { - let locator = XPATH.container + XPATH.itemToDeleteByDisplayName(itemDisplayName) + - "//div[@title='Click to show the inbound references']"; - await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - await this.clickOnElement(locator); - return await this.pause(2000); + waitForArchiveMenuDropDownHandleDisabled() { + return this.waitForElementDisabled(this.archiveMenuDropDownHandle, appConst.mediumTimeout); + } + + async clickOnShowReferencesButton(itemDisplayName) { + let buttonLocator = XPATH.showReferencesButton(itemDisplayName); + await this.waitForSpinnerNotVisible(); + await this.waitForInboundReferencesEntryDisplayed(); + await this.waitForElementDisplayed(buttonLocator, appConst.mediumTimeout); + await this.clickOnElement(buttonLocator); + return await this.pause(3000); } async getNumberInArchiveButton() { @@ -161,6 +176,14 @@ class DeleteContentDialog extends Page { return this.isElementDisplayed(this.archiveButton); } + async waitForArchiveButtonDisabled() { + return this.waitForElementDisabled(this.archiveButton, appConst.mediumTimeout); + } + + async waitForArchiveButtonEnabled() { + return this.waitForElementEnabled(this.archiveButton, appConst.mediumTimeout); + } + async isArchiveMenuDropDownHandleDisplayed() { return await this.isElementDisplayed(this.archiveMenuDropDownHandle); } @@ -171,55 +194,47 @@ class DeleteContentDialog extends Page { } async getDependantItemsName() { - let locator = XPATH.container + XPATH.dependantList + lib.H6_DISPLAY_NAME; + let locator = XPATH.container + XPATH.dependantListUl + lib.H6_DISPLAY_NAME; await this.waitForElementDisplayed(locator, appConst.mediumTimeout); return await this.getTextInDisplayedElements(locator); } - waitForHideDependantItemsLinkDisplayed() { - return this.waitForElementDisplayed(this.hideDependantItemsLink, appConst.mediumTimeout); - } - - waitForShowDependantItemsLinkDisplayed() { - let locator = XPATH.container + XPATH.showDependantItemsLink; - return this.waitForElementDisplayed(locator, appConst.mediumTimeout); - } - async clickOnHideDependantItemsLink() { - await this.waitForHideDependantItemsLinkDisplayed(); - return await this.clickOnElement(this.hideDependantItemsLink); + async waitForDependantsHeaderDisplayed() { + try { + return await this.waitForElementDisplayed(this.dependentsHeader, appConst.mediumTimeout); + } catch (err) { + await this.saveScreenshot(appConst.generateRandomName('err_dependants_header')); + throw new Error('Delete content dialog, dependants header is not displayed: ' + err); + } } - async clickShowDependantItemsLink() { - await this.waitForShowDependantItemsLinkDisplayed(); - return await this.clickOnElement(this.showDependantItemsLink, appConst.mediumTimeout); + async waitForShowReferencesButtonDisplayed(displayName) { + let locator = XPATH.showReferencesButton(displayName); + return await this.waitForElementDisplayed(locator, appConst.mediumTimeout); } - async getNumberInHideDependantItemsLink() { - let text = await this.getText(this.hideDependantItemsLink); - let startIndex = text.indexOf('('); - let endIndex = text.indexOf(')'); - return text.substring(startIndex + 1, endIndex); + async clickOnIgnoreInboundReferences() { + try { + await this.waitForIgnoreInboundReferencesButtonDisplayed(); + await this.clickOnElement(this.ignoreInboundReferencesButton); + return await this.pause(700); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_ignore_inbound_ref'); + throw new Error("Delete Content dialog, screenshot:" + screenshot + ' ' + err); + } } - async waitForNumberInHideDependantItemsLink(number) { - await this.waitForHideDependantItemsLinkDisplayed(); - await this.getBrowser().waitUntil(async () => { - let text = await this.getText(this.hideDependantItemsLink); - return text.includes(number); - }, {timeout: appConst.mediumTimeout, timeoutMsg: "Error getting a number in dependant items link: "}); + waitForIgnoreInboundReferencesButtonDisplayed() { + return this.waitForElementDisplayed(this.ignoreInboundReferencesButton, appConst.mediumTimeout); } - async getNumberInShowDependantItemsLink() { - let text = await this.getText(this.showDependantItemsLink); - let startIndex = text.indexOf('('); - let endIndex = text.indexOf(')'); - return text.substring(startIndex + 1, endIndex); + waitForIgnoreInboundReferencesButtonNotDisplayed() { + return this.waitForElementNotDisplayed(this.ignoreInboundReferencesButton, appConst.mediumTimeout); } - getDependantNames() { - let locator = XPATH.container + XPATH.dependantList + "//div[contains(@id,'DependantItemViewer')]" + lib.H6_DISPLAY_NAME; - return this.getTextInDisplayedElements(locator); + async waitForInboundReferencesEntryDisplayed() { + return await this.waitForElementDisplayed(XPATH.inboundErrorStateEntry, appConst.mediumTimeout) } } diff --git a/testing/page_objects/details_panel/base.dependencies.widget.js b/testing/page_objects/details_panel/base.dependencies.widget.js index 97d2bcab..69eccbfd 100644 --- a/testing/page_objects/details_panel/base.dependencies.widget.js +++ b/testing/page_objects/details_panel/base.dependencies.widget.js @@ -11,47 +11,65 @@ class BaseDependenciesWidget extends Page { await this.waitForElementDisplayed(this.showOutboundButton, appConst.shortTimeout); await this.waitForElementEnabled(this.showOutboundButton, appConst.shortTimeout); await this.clickOnElement(this.showOutboundButton); - return await this.pause(1000); + return await this.pause(2000); } catch (err) { await this.saveScreenshot('err_outbound_button'); throw new Error('Show Outbound button is not visible in ' + err); } } - clickOnShowInboundButton() { - return this.clickOnElement(this.showInboundButton); + async clickOnShowInboundButton() { + await this.clickOnElement(this.showInboundButton); + await this.pause(1000); } waitForNoOutgoingDependenciesMessage() { - return this.waitForElementDisplayed("//div[@class='dependencies-container outbound no-dependencies']"); + return this.waitForElementDisplayed("//div[@class='dependencies-container outbound no-dependencies']", appConst.mediumTimeout); } - getNumberOutboundItems() { - return this.waitForElementDisplayed(this.showOutboundButton, appConst.shortTimeout).then(() => { - return this.getText(this.showOutboundButton); - }).then(result => { - let startIndex = result.indexOf('('); - let endIndex = result.indexOf(')'); - return result.substring(startIndex + 1, endIndex); - }) + waitForNoIncomingDependenciesMessage() { + return this.waitForElementDisplayed("//div[contains(@class,'inbound no-dependencies')]", appConst.mediumTimeout); } - waitForOutboundButtonNotVisible() { - return this.waitForElementNotDisplayed(this.showOutboundButton, appConst.shortTimeout).catch(err => { - this.saveScreenshot('err_outbound_button_should_be_hidden'); - throw new Error('showOutboundButton still visible in ' + err); - }); + getContentDisplayName() { + let locator = this.dependenciesWidget + "//div[contains(@id,'NamesView')]//h6[contains(@class,'main-name')]"; + return this.getText(locator); + } + + getContentName() { + let locator = this.dependenciesWidget + "//p[contains(@class,'sub-name')]"; + return this.getText(locator); + } + + async getNumberOutboundItems() { + await this.waitForElementDisplayed(this.showOutboundButton, appConst.shortTimeout); + let text = await this.getText(this.showOutboundButton); + let startIndex = text.indexOf('('); + let endIndex = text.indexOf(')'); + return text.substring(startIndex + 1, endIndex); + } + + async waitForOutboundButtonNotVisible() { + try { + await this.waitForElementNotDisplayed(this.showOutboundButton, appConst.shortTimeout) + } catch (err) { + let screenshot = await this.saveScreenshot('err_outbound_button_should_be_hidden'); + throw new Error('show Outbound Button is visible, screenshot' + screenshot + ' ' + err); + } } isInboundButtonVisible() { return this.isElementDisplayed(this.showInboundButton); } - waitForOutboundButtonVisible() { - return this.waitForElementDisplayed(this.showOutboundButton, appConst.shortTimeout).catch(err => { - this.saveScreenshot('err_outbound_button'); + async waitForOutboundButtonVisible() { + try { + await this.waitForElementDisplayed(this.showOutboundButton, appConst.shortTimeout); + await this.pause(500); + } catch (err) { + await this.saveScreenshotUniqueName('err_outbound_button'); throw new Error('showOutboundButton is not visible in ' + err); - }); + } } waitForInboundButtonVisible() { diff --git a/testing/page_objects/details_panel/base.details.panel.js b/testing/page_objects/details_panel/base.details.panel.js index 01929ab3..5539ccbc 100644 --- a/testing/page_objects/details_panel/base.details.panel.js +++ b/testing/page_objects/details_panel/base.details.panel.js @@ -21,7 +21,8 @@ class BaseDetailsPanel extends Page { } async getSelectedOptionInWidgetSelectorDropdown() { - let selector = this.widgetSelectorDropdown + "//div[@class='selected-option']//h6"; + let selector = this.widgetSelectorDropdown + lib.H6_DISPLAY_NAME; + await this.waitForElementDisplayed(selector, appConst.mediumTimeout); return await this.getText(selector); } @@ -54,17 +55,19 @@ class BaseDetailsPanel extends Page { let widgetSelectorDropdown = new WidgetSelectorDropdown(); await this.clickOnWidgetSelectorDropdownHandle(); await widgetSelectorDropdown.clickOnOptionByDisplayName(appConst.WIDGET_TITLE.VERSION_HISTORY, this.container); - await widgetSelectorDropdown.clickOnApplySelectionButton(); + await this.pause(900); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_open_versions'); throw new Error(`Error occurred in widget selector dropdown, Version History, screenshot ${screenshot}: ` + err); } } + // type Version History in Options filter input then click on the filtered item async filterAndOpenVersionHistory() { try { let widgetSelectorDropdown = new WidgetSelectorDropdown(); - await widgetSelectorDropdown.selectFilteredWidgetItemAndClickOnOk(appConst.WIDGET_TITLE.VERSION_HISTORY); + await widgetSelectorDropdown.clickOnDropdownHandle(); + await widgetSelectorDropdown.selectFilteredWidgetItem(appConst.WIDGET_TITLE.VERSION_HISTORY); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_open_versions'); throw new Error(`Error occurred in widget selector dropdown, Version History, screenshot ${screenshot}: ` + err); @@ -75,7 +78,6 @@ class BaseDetailsPanel extends Page { let widgetSelectorDropdown = new WidgetSelectorDropdown(); await this.clickOnWidgetSelectorDropdownHandle(); await widgetSelectorDropdown.clickOnOptionByDisplayName(itemName); - await widgetSelectorDropdown.clickOnApplySelectionButton(); } getWidgetSelectorDropdownOptions() { @@ -87,16 +89,14 @@ class BaseDetailsPanel extends Page { async openDependencies() { let widgetSelectorDropdown = new WidgetSelectorDropdown(); await this.clickOnWidgetSelectorDropdownHandle(); - await widgetSelectorDropdown.clickOnOptionByDisplayName(appConst.WIDGET_TITLE.DEPENDENCIES); - await widgetSelectorDropdown.clickOnApplySelectionButton(); + await widgetSelectorDropdown.clickOnOptionByDisplayName(appConst.WIDGET_SELECTOR_OPTIONS.DEPENDENCIES); } async openLayers() { try { let widgetSelectorDropdown = new WidgetSelectorDropdown(); await this.clickOnWidgetSelectorDropdownHandle(); - await widgetSelectorDropdown.clickOnOptionByDisplayName(appConst.WIDGET_TITLE.LAYERS); - await widgetSelectorDropdown.clickOnApplySelectionButton(); + await widgetSelectorDropdown.clickOnOptionByDisplayName(appConst.WIDGET_SELECTOR_OPTIONS.LAYERS); } catch (err) { throw new Error("Error during opening 'Layers widget'" + err); } @@ -106,8 +106,7 @@ class BaseDetailsPanel extends Page { try { let widgetSelectorDropdown = new WidgetSelectorDropdown(); await this.clickOnWidgetSelectorDropdownHandle(); - await widgetSelectorDropdown.clickOnOptionByDisplayName(appConst.WIDGET_TITLE.DETAILS); - await widgetSelectorDropdown.clickOnApplySelectionButton(); + await widgetSelectorDropdown.clickOnOptionByDisplayName(appConst.WIDGET_SELECTOR_OPTIONS.DETAILS); } catch (err) { throw new Error("Error occurred during opening 'Details widget'" + err); } @@ -115,8 +114,7 @@ class BaseDetailsPanel extends Page { async clickOnEmulatorOptionsItem() { let widgetSelectorDropdown = new WidgetSelectorDropdown(); - await widgetSelectorDropdown.clickOnOptionByDisplayName(appConst.WIDGET_TITLE.EMULATOR); - await widgetSelectorDropdown.clickOnApplySelectionButton(); + await widgetSelectorDropdown.clickOnOptionByDisplayName(appConst.WIDGET_SELECTOR_OPTIONS.EMULATOR); } async openEmulatorWidget() { @@ -137,7 +135,6 @@ class BaseDetailsPanel extends Page { let widgetSelectorDropdown = new WidgetSelectorDropdown(); await this.clickOnWidgetSelectorDropdownHandle(); await widgetSelectorDropdown.clickOnOptionByDisplayName(appConst.WIDGET_TITLE.VARIANTS); - await widgetSelectorDropdown.clickOnApplySelectionButton(); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_variants_widget'); throw new Error(`Error during opening Variants widget, screenshot:${screenshot} ` + err); @@ -149,12 +146,12 @@ class BaseDetailsPanel extends Page { let widgetSelectorDropdown = new WidgetSelectorDropdown(); await this.clickOnWidgetSelectorDropdownHandle(); await widgetSelectorDropdown.clickOnOptionByDisplayName(appConst.WIDGET_TITLE.PUBLISHING_REPORT); - await widgetSelectorDropdown.clickOnApplySelectionButton(); } catch (err) { - let screenshot = await this.saveScreenshotUniqueName('err_open_publish_report'); - throw new Error("Error when opening Publishing report widget: " + err); + let screenshot = await this.saveScreenshotUniqueName('err_publish_report_widget'); + throw new Error(`Error during opening Variants widget, screenshot:${screenshot} ` + err); } } + } module.exports = BaseDetailsPanel; diff --git a/testing/page_objects/details_panel/base.layers.widget.js b/testing/page_objects/details_panel/base.layers.widget.js index 61374920..a5390dc8 100644 --- a/testing/page_objects/details_panel/base.layers.widget.js +++ b/testing/page_objects/details_panel/base.layers.widget.js @@ -28,7 +28,7 @@ class BaseLayersWidget extends Page { waitForWidgetLoaded() { return this.waitForElementDisplayed(this.layersWidget, appConst.shortTimeout).catch(err => { - throw new Error('Browse Panel: Layers Widget is not loaded in ' + appConst.shortTimeout); + throw new Error('Browse Panel: Layers Widget is not loaded in ' + appConst.shortTimeout + ' ' + err); }); } @@ -64,27 +64,14 @@ class BaseLayersWidget extends Page { await this.waitForElementDisplayed(locator, appConst.mediumTimeout); return await this.waitForElementEnabled(locator, appConst.mediumTimeout); } catch (err) { - let screenshot = appConst.generateRandomName('err_edit_btn_widget'); - await this.saveScreenshot(screenshot); - throw new Error("Layer widget - Error 'Edit' button in the layer view item, screenshot: " + screenshot + ' ' + err); - } - } - - async clickOnWidgetItem(layerName) { - try { - let locator = this.widgetItemView + xpath.layerViewByName(layerName); - await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - return await this.clickOnElement(locator); - } catch (err) { - let screenshot = appConst.generateRandomName('widget_item'); - await this.saveScreenshot(screenshot); - throw new Error("Error after clicking on the widget-item, screenshot: " + screenshot + ' ' + err); + throw new Error("Error getting button in the layer view item: " + err); } } async waitForOpenButtonEnabled(layerName) { try { - let locator = this.widgetItemView + xpath.layerViewByName(layerName) + xpath.openButton; + let locator = this.widgetItemView + xpath.layerViewByName(layerName) + + "/following-sibling::div[contains(@id,'LayerContentViewFooter')]/button[child::span[text()='Open']]"; await this.waitForElementDisplayed(locator, appConst.mediumTimeout); return await this.waitForElementEnabled(locator, appConst.mediumTimeout); } catch (err) { @@ -92,34 +79,17 @@ class BaseLayersWidget extends Page { } } - async clickOnOpenButton(layerName) { - try { - let locator = this.widgetItemView + xpath.layerViewByName(layerName) + xpath.openButton; - await this.waitForOpenButtonEnabled(layerName); - await this.clickOnElement(locator); - await this.pause(700); - } catch (err) { - let screenshot = appConst.generateRandomName('widget_item_open'); - await this.saveScreenshot(screenshot); - throw new Error("Error after clicking on the Open button, screenshot: " + screenshot + ' ' + err); - } - } async clickOnLocalizeButton(layerName) { let locator = this.widgetItemView + xpath.layerViewByName(layerName) + "/following-sibling::div[contains(@id,'LayerContentViewFooter')]/button/span[text()='Localize']"; await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - await this.clickOnElement(locator); - return await this.pause(1000); - } - - async waitForShowAllButtonDisplayed() { - return await this.waitForElementDisplayed(this.showAllButton, appConst.mediumTimeout); + return await this.clickOnElement(locator); } - async clickOnShowAllButton(layerName) { + async clickOnShowAllButton() { let layersContentTreeDialog = new LayersContentTreeDialog(); - await this.waitForShowAllButtonDisplayed(); + await this.waitForElementDisplayed(this.showAllButton, appConst.mediumTimeout); await this.clickOnElement(this.showAllButton); await layersContentTreeDialog.waitForDialogLoaded(); return layersContentTreeDialog; @@ -138,11 +108,40 @@ class BaseLayersWidget extends Page { return displayName + postfix; } - async getContentStatus(layerName) { + async getContentStatus() { let locator = this.widgetItemView + "//div[contains(@id,'LayerContentViewHeader')]//div[contains(@class,'status')]"; await this.waitForElementDisplayed(locator); return await this.getText(locator); } + + async waitForShowAllButtonDisplayed() { + return await this.waitForElementDisplayed(this.showAllButton, appConst.mediumTimeout); + } + + async clickOnWidgetItem(layerName) { + try { + let locator = this.widgetItemView + xpath.layerViewByName(layerName); + await this.waitForElementDisplayed(locator, appConst.mediumTimeout); + return await this.clickOnElement(locator); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('widget_item'); + throw new Error(`Error after clicking on the widget-item, screenshot: ${screenshot} ` + err); + } + } + + async clickOnOpenButton(layerName) { + try { + let locator = this.widgetItemView + xpath.layerViewByName(layerName) + xpath.openButton; + await this.waitForOpenButtonEnabled(layerName); + await this.clickOnElement(locator); + await this.pause(700); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('widget_item_open'); + throw new Error("Error after clicking on the Open button, screenshot: " + screenshot + ' ' + err); + } + } + + } module.exports = BaseLayersWidget; diff --git a/testing/page_objects/details_panel/base.publish.report.widget.js b/testing/page_objects/details_panel/base.publish.report.widget.js index 3710b0af..0a230dde 100644 --- a/testing/page_objects/details_panel/base.publish.report.widget.js +++ b/testing/page_objects/details_panel/base.publish.report.widget.js @@ -5,8 +5,6 @@ const Page = require('../page'); const appConst = require('../../libs/app_const'); const lib = require('../../libs/elements'); -const xpath = {}; - class BasePublishReportWidget extends Page { get generateButton() { @@ -44,7 +42,7 @@ class BasePublishReportWidget extends Page { async waitForWidgetLoaded() { try { - let locator = "//div[contains(@id,'WidgetSelectedOptionView')]" + lib.itemByName('Compare published versions'); + let locator = "//div[contains(@id,'WidgetsSelectionRow')]" + lib.itemByName('Compare published versions'); return await this.waitForElementDisplayed(locator, appConst.mediumTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_publish_report_load'); @@ -77,7 +75,7 @@ class BasePublishReportWidget extends Page { return await this.waitForElementDisabled(this.generateButton, appConst.mediumTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_generate_btn_widget'); - throw new Error("Publish report widget - Error 'Generate' button should be disabled, screenshot: " + screenshot + ' ' + err); + throw new Error(`Publish report widget - Error 'Generate' button should be disabled, screenshot: ${screenshot} ` + err); } } @@ -87,7 +85,7 @@ class BasePublishReportWidget extends Page { return await this.clickOnElement(this.generateButton); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_click_on_generate'); - throw new Error("Error after clicking on Generate button, screenshot: " + screenshot + ' ' + err); + throw new Error(`Error after clicking on Generate button, screenshot:${screenshot} ` + err); } } @@ -106,7 +104,7 @@ class BasePublishReportWidget extends Page { return await this.waitForElementDisplayed(this.fromDateInput, appConst.mediumTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_publish_rep_from_date'); - throw new Error("PublishReport From date text input should be displayed, screenshot: " + screenshot + ' ' + err); + throw new Error(`PublishReport From date text input should be displayed, screenshot: ${screenshot} ` + err); } } @@ -115,7 +113,7 @@ class BasePublishReportWidget extends Page { return await this.waitForElementNotDisplayed(this.fromDateInput, appConst.mediumTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_publish_rep_from_date'); - throw new Error("PublishReport From date text input should not be displayed, screenshot: " + screenshot + ' ' + err); + throw new Error(`PublishReport From date text input should not be displayed, screenshot: ${screenshot} ` + err); } } diff --git a/testing/page_objects/details_panel/base.versions.widget.js b/testing/page_objects/details_panel/base.versions.widget.js index d8514783..8c288757 100644 --- a/testing/page_objects/details_panel/base.versions.widget.js +++ b/testing/page_objects/details_panel/base.versions.widget.js @@ -8,29 +8,130 @@ const lib = require('../../libs/elements'); const xpath = { versionsList: "//ul[contains(@id,'VersionHistoryList')]", versionItemExpanded: "//li[contains(@class,'version-list-item expanded')]", - versionItem: "//li[contains(@class,'version-list-item') and not(contains(@class,'publish-action'))]", - archivedItems: "//li[contains(@id,'VersionHistoryListItem')and descendant::h6[contains(.,'Archived')]]", - restoredItems: "//li[contains(@id,'VersionHistoryListItem')and descendant::h6[contains(.,'Restored')]]", - versionItemByDisplayName: displayName => `${lib.itemByDisplayName(displayName)}`, + versionItem: "//li[contains(@class,'version-list-item') and child::div[not(contains(@class,'publish-action')) ] and not(descendant::h6[contains(.,'Permissions updated')])]", + itemByDisplayName: displayName => `${lib.itemByDisplayName(displayName)}`, anyItemByHeader: header => `//li[contains(@class,'version-list-item') and descendant::h6[contains(.,'${header}')]]`, showChangesButtonLocator: ".//button[@title='Show changes']", + publishMessageDiv: "//div[contains(@class, 'publish-message')]", }; class BaseVersionsWidget extends Page { get compareWithCurrentVersionButton() { - return this.versionsWidget + lib.COMPARE_WITH_CURRENT_VERSION; + return this.versionsWidget + lib.VERSIONS_SHOW_CHANGES_BUTTON; } - get archivedItems() { - return this.versionsWidget + xpath.versionsList + xpath.archivedItems; + get revertButton() { + return this.versionsWidget + xpath.versionItemExpanded + "//button[child::span[text()='Revert']]"; } + //Count version items that contain 'Revert' button async countVersionItems() { - let items = await this.findElements(xpath.versionItem); + let items = await this.findElements(this.versionItems); return items.length; } + async waitForPermissionsUpdatedItemDisplayed() { + try { + await this.waitForElementDisplayed(this.permissionsUpdatedItems, appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_perm_updated'); + throw new Error("'Permissions updated' items are not displayed in the widget, screenshot: " + screenshot + " " + err); + } + } + + async countPermissionsUpdatedItems() { + try { + await this.waitForPermissionsUpdatedItemDisplayed(); + let items = await this.findElements(this.permissionsUpdatedItems); + return items.length; + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_perm_updated'); + throw new Error("Error when counting 'Permissions updated' items, screenshot: " + screenshot + " " + err); + } + } + + async countSortedItems() { + await this.waitForElementDisplayed(this.sortedItems, appConst.mediumTimeout) + let items = await this.findElements(this.sortedItems); + return items.length; + } + + async waitForPublishedItemDisplayed() { + try { + await this.waitForElementDisplayed(this.publishedItems, appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_published_item'); + throw new Error("'Published' items are not displayed in the widget, screenshot: " + screenshot + " " + err); + } + } + + async countPublishedItems() { + await this.waitForPublishedItemDisplayed(); + let items = await this.findElements(this.publishedItems); + return items.length; + } + + async waitForUnpublishedItemDisplayed() { + try { + await this.waitForElementDisplayed(this.unpublishedItems, appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_unpublished_item'); + throw new Error("'Unpublished' items are not displayed in the widget, screenshot: " + screenshot + " " + err); + } + } + + async countUnpublishedItems() { + await this.waitForUnpublishedItemDisplayed(); + let items = await this.findElements(this.unpublishedItems); + return items.length; + } + + async countMarkedAsReadyItems() { + await this.waitForElementDisplayed(this.markedAsReadyItems, appConst.mediumTimeout) + let items = await this.findElements(this.markedAsReadyItems); + return items.length; + } + + async countMovedItems() { + await this.waitForElementDisplayed(this.movedItems, appConst.mediumTimeout) + let items = await this.findElements(this.movedItems); + return items.length; + } + + async countRenamedItems() { + await this.waitForElementDisplayed(this.renamedItems, appConst.mediumTimeout) + let items = await this.findElements(this.renamedItems); + return items.length; + } + + async countEditedItems() { + await this.waitForElementDisplayed(this.editedItems, appConst.mediumTimeout) + let items = await this.findElements(this.editedItems); + return items.length; + } + + async countCreatedItems() { + await this.waitForElementDisplayed(this.createdItems, appConst.mediumTimeout) + let items = await this.findElements(this.createdItems); + return items.length; + } + + //click on a version and expand the content-version-item + async clickAndExpandVersion(index) { + try { + await this.waitForElementDisplayed(this.versionItems, appConst.mediumTimeout); + //get clickable items: + let items = await this.findElements(this.versionItems); + //click on the item: + await this.getBrowser().elementClick(items[index].elementId); + return await this.pause(300); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_expand_version'); + throw new Error(`Error occurred in Version Widget - screenshot: ${screenshot} ` + err); + } + } + //get all version items with the header then click on required item: async clickOnVersionItemByHeader(versionHeader, index) { try { @@ -44,8 +145,32 @@ class BaseVersionsWidget extends Page { await items[i].click(); return await this.pause(300); } catch (err) { - await this.saveScreenshot(appConst.generateRandomName("err_expand_version")); - throw new Error("Error when clicking on the version item: " + err); + let screenshot = await this.saveScreenshotUniqueName('err_expand_version'); + throw new Error(`Error occurred in Version Widget - screenshot: ${screenshot} ` + err); + } + } + + async getPublishMessagesFromPublishedItems() { + await this.waitForElementDisplayed(this.versionItems, appConst.mediumTimeout); + //get all version items with the header: + let locator = this.versionsWidget + xpath.anyItemByHeader(appConst.VERSIONS_ITEM_HEADER.PUBLISHED) + xpath.publishMessageDiv; + await this.waitForElementDisplayed(locator, appConst.mediumTimeout); + return await this.getTextInDisplayedElements(locator); + } + + async clickAndExpandVersionItemByHeader(versionHeader, index) { + try { + let i = index === undefined ? 0 : index; + await this.waitForElementDisplayed(this.versionItems, appConst.mediumTimeout); + //get clickable items: + let locator = this.versionItemByDisplayName(versionHeader); + let items = await this.findElements(locator); + //click on the item: + await items[i].click(); + return await this.pause(300); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_expand_version'); + throw new Error(`Error occurred in Version Widget - screenshot: ${screenshot} ` + err); } } @@ -64,30 +189,62 @@ class BaseVersionsWidget extends Page { }); } - async isRevertButtonDisplayed() { + async waitForRevertButtonNotDisplayed() { try { - let locator = xpath.versionsList + "//button[child::span[text()='Revert']]"; - let res = await this.getDisplayedElements(locator); - return res.length > 0; + return await this.waitForElementNotDisplayed(this.revertButton, appConst.mediumTimeout); } catch (err) { - await this.saveScreenshot("revert_version_button"); - throw new Error("Version Widget - " + err); + let screenshot = await this.saveScreenshotUniqueName('err_revert_button'); + throw new Error(`Revert button should not be displayed! screenshot: ${screenshot} ` + err); } } - async isActiveVersionButtonDisplayed() { + async waitForRevertButtonDisplayed() { try { - let locator = xpath.versionsList + "//button[child::span[text()='Active version']]"; - let res = await this.getDisplayedElements(locator); - return res.length > 0; + return await this.waitForElementDisplayed(this.revertButton, appConst.mediumTimeout); } catch (err) { - await this.saveScreenshot("active_version_button"); - throw new Error("Version Widget - " + err); + let screenshot = await this.saveScreenshotUniqueName('err_revert_button'); + throw new Error(`Revert button should be displayed! screenshot: ${screenshot} ` + err); } } - async waitForPublishedWidgetItemVisible() { - return await this.waitForElementDisplayed(this.publishActionItems, appConst.mediumTimeout); + async clickOnRevertButton() { + try { + await this.waitForElementDisplayed(this.revertButton, appConst.mediumTimeout); + await this.clickOnElement(this.revertButton); + return await this.pause(2000); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_revert_button'); + throw new Error("Version Widget - error when clicking on 'Revert' button, screenshot: " + screenshot + " " + err); + } + } + + async waitForRevertButtonDisabled() { + try { + let res = await this.getDisplayedElements(this.revertButton); + await res[0].waitForEnabled({timeout: 2000, reverse: true}); + return await this.pause(appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_revert_button'); + throw new Error(`Version Widget - 'Revert' button is not disabled, screenshot: ${screenshot} ` + err); + } + } + + async waitForMovedItemDisplayed() { + try { + return await this.waitForElementDisplayed(this.movedItems, appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_moved_item'); + throw new Error("'Moved' items are not displayed in the widget, screenshot: " + screenshot + " " + err); + } + } + + async waitForRenamedItemDisplayed() { + try { + return await this.waitForElementDisplayed(this.renamedItems, appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_renamed_item'); + throw new Error("'Renamed' items are not displayed in the widget, screenshot: " + screenshot + " " + err); + } } async getContentStatus() { @@ -96,16 +253,16 @@ class BaseVersionsWidget extends Page { return await this.getText(locator); } - async clickOnCompareWithCurrentVersionButton(index) { + async clickOnOnShowChangesButton(index) { try { //wait for the list of versions is loaded: await this.waitForElementDisplayed(this.versionsWidget + xpath.versionsList, appConst.mediumTimeout); - let elements = await this.findElements(this.compareWithCurrentVersionButton); - await elements[index].click(); + let buttons = await this.findElements(this.compareWithCurrentVersionButton); + await buttons[index].click(); return await this.pause(400); } catch (err) { - await this.saveScreenshot(appConst.generateRandomName("err_versions_widget")); - throw new Error("Version Widget - error when clicking on CompareWithCurrentVersionButton " + err); + let screenshot = await this.saveScreenshotUniqueName('err_click_on_show_changes'); + throw new Error(`Version Widget - error when clicking on Show changes button, screenshot: ${screenshot} ` + err); } } @@ -117,27 +274,47 @@ class BaseVersionsWidget extends Page { await buttonElements[0].click(); return await this.pause(200); } catch (err) { - await this.saveScreenshot(appConst.generateRandomName("err_click_on_compare")); - throw new Error("Version Widget - error when clicking on CompareWithCurrentVersionButton " + err); + let screenshot = await this.saveScreenshotUniqueName('err_click_on_compare'); + throw new Error(`Version Widget - error when clicking on Show changes button, screenshot: ${screenshot} ` + err); } } + async getUserNameInItemByHeader(itemHeader, index) { + try { + let itemLocator = this.versionsWidget + xpath.anyItemByHeader(itemHeader); + let versionItems = await this.findElements(itemLocator); + let locator = ".//p[contains(@class,'xp-admin-common-sub-name')]"; + let elements = await versionItems[index].$$(locator); + return await elements[0].getText(); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_expand_version'); + throw new Error(`Error when expand the version, screenshot: ${screenshot} ` + err); + } + } + + // Headers or displayNames :Created, Edited. Permissions Updated is excluded versionItemByDisplayName(displayName) { - return this.versionsWidget + xpath.versionsList + xpath.versionItemByDisplayName(displayName); + return this.versionsWidget + xpath.versionItem + xpath.itemByDisplayName(displayName); } - async getArchivedBy(index) { - let locator = this.versionsWidget + xpath.archivedItems + lib.P_SUB_NAME; - await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - let elements = await this.findElements(locator); - return await elements[index].getText(); + async waitForActiveVersionButtonDisplayed() { + try { + let locator = xpath.versionItemExpanded + "//button[child::span[text()='Active version']]"; + await this.waitForElementDisplayed(locator, appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName("active_version_button"); + throw new Error(`Version Widget - 'Active version' button is not displayed, screenshot: ${screenshot} ` + err); + } } - async getRestoredBy(index) { - let locator = this.versionsWidget + xpath.restoredItems + lib.P_SUB_NAME; - await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - let elements = await this.findElements(locator); - return await elements[index].getText(); + async waitForActiveVersionButtonNotDisplayed() { + try { + let locator = xpath.versionItemExpanded + "//button[child::span[text()='Active version']]"; + await this.waitForElementNotDisplayed(locator, appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('active_version_button'); + throw new Error(`Version Widget - 'Active version' button should not be displayed, screenshot: ${screenshot} ` + err); + } } async isShowChangesInVersionButtonDisplayed(itemHeader, index) { @@ -149,5 +326,3 @@ class BaseVersionsWidget extends Page { } module.exports = BaseVersionsWidget; - - diff --git a/testing/page_objects/details_panel/compare.content.versions.dialog.js b/testing/page_objects/details_panel/compare.content.versions.dialog.js deleted file mode 100644 index d79c5896..00000000 --- a/testing/page_objects/details_panel/compare.content.versions.dialog.js +++ /dev/null @@ -1,151 +0,0 @@ -/** - * Created on 01.04.2022 - */ -const Page = require('../page'); -const appConst = require('../../libs/app_const'); -const lib = require('../../libs/elements'); - -const XPATH = { - container: `//div[contains(@id,'CompareContentVersionsDialog')]`, - contentPanel: "//div[contains(@id,'ModalDialogContentPanel')]", - containerLeft: `//div[contains(@class,'container left')]`, - containerRight: `//div[contains(@class,'container right')]`, - containerBottom: `//div[@class='container bottom']`, - revertMenuButton: "//button[contains(@id,'Button') and descendant::li[contains(@id,'MenuItem') and text()='Revert']]", - revertMenuItem: "//ul[contains(@id,'Menu')]/li[contains(@id,'MenuItem') and text()='Revert']", -}; - -class CompareContentVersionsDialog extends Page { - - get leftRevertMenuButton() { - return XPATH.container + XPATH.containerLeft + XPATH.revertMenuButton; - } - - get rightRevertMenuButton() { - return XPATH.container + XPATH.containerRight + XPATH.revertMenuButton; - } - - get olderVersionDropdownHandle() { - return XPATH.container + XPATH.containerLeft + lib.DROP_DOWN_HANDLE; - } - - get cancelButtonTop() { - return XPATH.container + lib.CANCEL_BUTTON_TOP; - } - - get currentVersionDropdownHandle() { - return XPATH.container + XPATH.containerRight + lib.DROP_DOWN_HANDLE; - } - - get showEntireContent() { - return XPATH.container + lib.SHOW_ENTIRE_CONTENT_CHECKBOX_DIV + "//label"; - } - - async clickOnLeftRevertMenuButton() { - await this.waitForLeftRevertButtonDisplayed(); - await this.clickOnElement(this.leftRevertMenuButton); - return await this.pause(300); - } - - async waitForLeftRevertMenuItemDisplayed() { - let selector = XPATH.container + XPATH.containerRight + XPATH.revertMenuItem; - } - - async waitForLeftRevertButtonDisplayed() { - return await this.waitForElementDisplayed(this.leftRevertMenuButton, appConst.mediumTimeout); - } - - async waitForLeftRevertMenuButtonNotDisplayed() { - try { - return await this.waitForElementNotDisplayed(this.leftRevertMenuButton, appConst.mediumTimeout); - } catch (err) { - await this.saveScreenshot(appConst.generateRandomName("err_compare_versions_menu")); - throw new Error("Left revert menu button should not be displayed: " + err); - } - } - - async waitForRightRevertMenuButtonDisplayed() { - return await this.waitForElementDisplayed(this.leftRevertMenuButton, appConst.mediumTimeout); - } - - async waitForRightRevertMenuButtonNotDisplayed() { - try { - return await this.waitForElementNotDisplayed(this.rightRevertMenuButton, appConst.mediumTimeout); - } catch (err) { - await this.saveScreenshot(appConst.generateRandomName("err_compare_versions_menu")); - throw new Error("Right revert menu button should not be displayed: " + err); - } - } - - async waitForRightRevertMenuButtonDisabled() { - return await this.waitForElementDisabled(this.rightRevertMenuButton, appConst.mediumTimeout); - } - - async waitForLeftRevertMenuButtonEnabled() { - return await this.waitForElementEnabled(this.leftRevertMenuButton, appConst.mediumTimeout); - } - - async clickOnRightRevertButton() { - await this.waitForElementDisplayed(this.leftRevertMenuButton, appConst.mediumTimeout); - return await this.clickOnElement(this.leftRevertMenuButton); - } - - async clickOnCancelTopButton() { - return await this.clickOnElement(this.leftRevertMenuButton); - } - - waitForDialogOpened() { - return this.waitForElementDisplayed(XPATH.container, appConst.mediumTimeout).catch(err => { - throw new Error("CompareContentVersions Dialog is not loaded " + err); - }) - } - - waitForDialogClosed() { - return this.waitForElementNotDisplayed(XPATH.container, appConst.mediumTimeout).catch(err => { - throw new Error("CompareContentVersions Dialog must be closed " + err); - }) - } - - async clickOnCancelButtonTop() { - await this.clickOnElement(this.cancelButtonTop); - return await this.waitForDialogClosed(); - } - - async clickOnShowEntireContentCheckbox() { - return this.clickOnElement(this.showEntireContent); - } - - async getTypeProperty() { - let locator = XPATH.container + "//li[@data-key='type']//pre"; - await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - return await this.getText(locator); - } - - async clickOnLeftSelectorDropdownHandle() { - let locator = XPATH.containerLeft + lib.DROP_DOWN_HANDLE; - await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - await this.waitForElementEnabled(locator, appConst.mediumTimeout); - return await this.clickOnElement(locator); - } - - async clickOnRightSelectorDropdownHandle() { - let locator = XPATH.containerRight + lib.DROP_DOWN_HANDLE; - await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - await this.waitForElementEnabled(locator, appConst.mediumTimeout); - return await this.clickOnElement(locator); - } - - async clickOnOptionInLeftVersionsSelector(optionName) { - let locator = XPATH.containerLeft + `//div[contains(@class,'slick-cell') and descendant::h6[contains(.,'${optionName}')]]`; - await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - return await this.clickOnElement(locator); - } - - async waitForContentPanelIsEmpty() { - let locator = XPATH.container + XPATH.contentPanel + "//div[contains(@class,'jsondiffpatch-delta empty')]"; - await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - return await this.getText(locator + "//h3"); - } -} - -module.exports = CompareContentVersionsDialog; diff --git a/testing/page_objects/details_panel/create.variant.dialog.js b/testing/page_objects/details_panel/create.variant.dialog.js index 39dc3f5d..34b09816 100644 --- a/testing/page_objects/details_panel/create.variant.dialog.js +++ b/testing/page_objects/details_panel/create.variant.dialog.js @@ -60,8 +60,7 @@ class CreateVariantDialog extends Page { try { return await this.waitForElementDisplayed(XPATH.container, appConst.mediumTimeout) } catch (err) { - let screenshot = appConst.generateRandomName('err_variants_dlg'); - await this.saveScreenshot(screenshot); + let screenshot = await this.saveScreenshotUniqueName('err_variants_dlg'); throw new Error(`Create Variant Dialog is not loaded ${screenshot} ` + err); } } @@ -70,8 +69,7 @@ class CreateVariantDialog extends Page { try { return await this.waitForElementNotDisplayed(XPATH.container, appConst.mediumTimeout) } catch (err) { - let screenshot = appConst.generateRandomName('err_variants_dlg'); - await this.saveScreenshot(screenshot); + let screenshot = await this.saveScreenshotUniqueName('err_variants_dlg'); throw new Error(`Create Variant Dialog is not closed ${screenshot} ` + err); } } diff --git a/testing/page_objects/details_panel/edit.settings.dialog.js b/testing/page_objects/details_panel/edit.settings.dialog.js index 968a7d54..5c640891 100644 --- a/testing/page_objects/details_panel/edit.settings.dialog.js +++ b/testing/page_objects/details_panel/edit.settings.dialog.js @@ -4,7 +4,8 @@ const Page = require('../page'); const appConst = require('../../libs/app_const'); const lib = require('../../libs/elements'); -const LoaderComboBox = require('../components/loader.combobox'); +const LocaleSelectorDropdown = require('../components/selectors/locale.selector.dropdown'); +const PrincipalComboBox = require('../components/selectors/principal.combobox.dropdown') const xpath = { container: `//div[contains(@id,'EditPropertiesDialog')]`, @@ -35,11 +36,7 @@ class EditSettingDialog extends Page { get languageFilterInput() { - return xpath.container + xpath.localeCombobox + lib.COMBO_BOX_OPTION_FILTER_INPUT; - } - - get ownerFilterInput() { - return xpath.container + xpath.ownerCombobox + lib.COMBO_BOX_OPTION_FILTER_INPUT; + return xpath.container + xpath.localeCombobox + lib.OPTION_FILTER_INPUT; } get removeLanguageButton() { @@ -87,26 +84,22 @@ class EditSettingDialog extends Page { async filterOptionsAndSelectLanguage(language) { try { - await this.typeTextInInput(this.languageFilterInput, language); - await this.pause(300); - let loaderComboBox = new LoaderComboBox(); - await loaderComboBox.selectOption(language); - await this.pause(300); + let localeSelectorDropdown = new LocaleSelectorDropdown(); + await localeSelectorDropdown.clickOnFilteredLanguage(language); } catch (err) { - await this.saveScreenshot(appConst.generateRandomName('err_option')); - throw new Error('Edit Setting dialog, language selector :' + err); + let screenshot = await this.saveScreenshotUniqueName('err_option'); + throw new Error(`Error occurred in Edit Setting dialog, language selector , screenshot: ${screenshot} ` + err); } } async filterOptionsAndSelectOwner(owner) { try { - await this.typeTextInInput(this.ownerFilterInput, owner); - let loaderComboBox = new LoaderComboBox(); - await loaderComboBox.selectOption(owner); + let principalComboBox = new PrincipalComboBox(); + await principalComboBox.selectFilteredUser(owner, xpath.container); return await this.pause(200); } catch (err) { - this.saveScreenshot(appConst.generateRandomName('err_option')); - throw new Error('Settings form, language selector :' + err); + let screenshot = await this.saveScreenshotUniqueName('err_option'); + throw new Error(`Error occurred in Settings form, language selector, screenshot : ${screenshot}` + err); } } @@ -116,8 +109,8 @@ class EditSettingDialog extends Page { await this.waitForElementDisplayed(selector, appConst.mediumTimeout); return await this.getText(selector); } catch (err) { - await this.saveScreenshot(appConst.generateRandomName('err_pr_wizard_language')); - throw new Error('Edit Setting dialog, error during getting the selected language. ' + err); + let screenshot = await this.saveScreenshotUniqueName('err_lang'); + throw new Error('Error occurred in Edit Setting dialog, the selected language. screenshot: ' + screenshot + ' ' + err); } } @@ -141,7 +134,7 @@ class EditSettingDialog extends Page { await this.clickOnElement(this.removeLanguageButton); return await this.pause(500); } catch (err) { - this.saveScreenshot('err_click_on_remove_language_icon'); + await this.saveScreenshot("err_click_on_remove_language_icon"); throw new Error('Error when removing the language! ' + err); } } @@ -151,7 +144,7 @@ class EditSettingDialog extends Page { await this.clickOnElement(this.removeOwnerButton); return await this.pause(500); } catch (err) { - this.saveScreenshot("err_click_on_remove_owner_icon"); + await this.saveScreenshot("err_click_on_remove_owner_icon"); throw new Error('Error when removing the owner! ' + err); } } @@ -163,10 +156,6 @@ class EditSettingDialog extends Page { waitForLanguageOptionsFilterDisplayed() { return this.waitForElementDisplayed(this.languageFilterInput, appConst.mediumTimeout); } - - isOwnerOptionsFilterVisible() { - return this.isElementDisplayed(this.ownerFilterInput); - } } module.exports = EditSettingDialog; diff --git a/testing/page_objects/edit.permissions.dialog.js b/testing/page_objects/edit.permissions.dialog.js index c2441da3..d63564d8 100644 --- a/testing/page_objects/edit.permissions.dialog.js +++ b/testing/page_objects/edit.permissions.dialog.js @@ -1,9 +1,11 @@ const Page = require('./page'); const appConst = require('../libs/app_const'); const lib = require('../libs/elements'); -const ComboBox = require('./components/loader.combobox'); +const AccessControlComboBox = require('./components/selectors/access.control.combobox'); const xpath = { container: `//div[contains(@id,'EditPermissionsDialog')]`, + accessSelector: "//div[contains(@id,'AccessSelector')]", + contentPath: "//p[@class='path']", applyButton: `//button[contains(@id,'DialogButton') and child::span[contains(.,'Apply')]]`, cancelButton: `//button/span[text()='Cancel']`, overwriteChildPermissionsCheckbox: `//div[contains(@class,'overwrite-child')]`, @@ -13,16 +15,14 @@ const xpath = { permissionToggleByOperationName: name => `//a[contains(@id,'PermissionToggle') and text()='${name}']`, aclEntryByName: name => `//div[contains(@id,'PrincipalContainerSelectedOptionView') and descendant::p[contains(@class,'sub-name') and contains(.,'${name}')]]`, + aclEntryByDisplayName: + displayName => `//div[contains(@id,'PrincipalContainerSelectedOptionView') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]`, menuItemByName: name => `//li[contains(@id,'TabMenuItem') and child::a[text()='${name}']]`, }; class EditPermissionsDialog extends Page { - get principalsOptionFilterInput() { - return xpath.container + lib.COMBO_BOX_OPTION_FILTER_INPUT; - } - get cancelButton() { return xpath.container + xpath.cancelButton; } @@ -39,6 +39,10 @@ class EditPermissionsDialog extends Page { return xpath.container + xpath.inheritPermissionsCheckbox; } + get contentPath() { + return xpath.container + xpath.contentPath; + } + async waitForDialogLoaded() { await this.waitForElementDisplayed(this.applyButton, appConst.mediumTimeout); return await this.pause(300); @@ -67,16 +71,20 @@ class EditPermissionsDialog extends Page { let selector = xpath.container + xpath.aclEntryByName(principalName) + lib.REMOVE_ICON; return this.clickOnElement(selector).catch(err => { this.saveScreenshot("err_remove_acl_entry"); - throw new Error("Error when trying to remove acl entry " + err); + throw new Error("Error when remove acl entry " + err); }); } - //filters and select a principal - filterAndSelectPrincipal(principalDisplayName) { - let comboBox = new ComboBox(); - return comboBox.typeTextAndSelectOption(principalDisplayName, xpath.container).then(() => { + // filters and select a principal + async filterAndSelectPrincipal(principalDisplayName) { + try { + let accessControlComboBox = new AccessControlComboBox(); + await accessControlComboBox.selectFilteredPrincipalAndClickOnApply(principalDisplayName, xpath.container); console.log("Edit Permissions Dialog, principal is selected: " + principalDisplayName); - }) + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_perm_dlg'); + throw new Error("Error during updating permissions, screenshot:" + screenshot + " " + err); + } } //finds an entry, clicks on 'tab-menu-button' (Can Write or Can Read or Custom...) and selects new required 'operation' @@ -111,14 +119,23 @@ class EditPermissionsDialog extends Page { async clickOnApplyButton() { try { + await this.waitForApplyButtonEnabled(); await this.clickOnElement(this.applyButton); return await this.pause(500); } catch (err) { - this.saveScreenshot('err_click_on_apply_button_permis_dialog'); + await this.saveScreenshot('err_click_on_apply_button_permis_dialog'); throw new Error('Error when clicking Apply dialog must be closed ' + err); } } + waitForApplyButtonEnabled() { + return this.waitForElementEnabled(this.cancelButton, appConst.mediumTimeout); + } + + waitForApplyButtonDisabled() { + return this.waitForElementDisabled(this.applyButton, appConst.mediumTimeout); + } + async isOperationAllowed(principalName, operation) { let permToggle = xpath.permissionToggleByOperationName(operation); let selector = xpath.aclEntryByName(principalName) + permToggle; @@ -141,7 +158,7 @@ class EditPermissionsDialog extends Page { await this.clickOnElement(this.inheritPermissionsCheckbox + '/label'); return await this.pause(500); } catch (err) { - this.saveScreenshot('err_click_on_inherit_permis_dialog'); + await this.saveScreenshot('err_click_on_inherit_permis_dialog'); throw new Error('Error when clicking on Inherit permissions ' + err); } } @@ -164,6 +181,32 @@ class EditPermissionsDialog extends Page { throw new Error('Error when checking Overwrite child permissions link ' + err); }) } + + async waitForAccessSelectorDisabled(principalName) { + let locator = xpath.aclEntryByDisplayName(principalName) + xpath.accessSelector; + await this.getBrowser().waitUntil(async () => { + let result = await this.getAttribute(locator, "class"); + return result.includes("disabled"); + }, {timeout: appConst.mediumTimeout, timeoutMsg: "Access selector should be disabled "}); + } + + async waitForAccessSelectorEnabled(principalDisplayName) { + let locator = xpath.aclEntryByDisplayName(principalDisplayName) + xpath.accessSelector; + await this.getBrowser().waitUntil(async () => { + let result = await this.getAttribute(locator, "class"); + return !result.includes("disabled"); + }, {timeout: appConst.mediumTimeout, timeoutMsg: "Access selector should be enabled "}); + } + + getContentPath() { + return this.getText(this.contentPath); + } + + async clickOnCancelButton() { + await this.waitForElementDisplayed(this.cancelButton, appConst.mediumTimeout); + return await this.clickOnElement(this.cancelButton); + } } + module.exports = EditPermissionsDialog; diff --git a/testing/page_objects/page.js b/testing/page_objects/page.js index 8bf60f95..d1bf5cc5 100644 --- a/testing/page_objects/page.js +++ b/testing/page_objects/page.js @@ -279,13 +279,19 @@ class Page { return await element.waitForDisplayed({timeout: ms}); } - waitForSpinnerNotVisible(ms) { - let timeout1; - timeout1 = ms === undefined ? appConst.longTimeout : ms; - let message = 'Spinner still displayed! timeout is ' + timeout1; - return this.browser.waitUntil(() => { - return this.isElementNotDisplayed("//div[@class='spinner']"); - }, {timeout: timeout1, timeoutMsg: message}); + async waitForSpinnerNotVisible(ms) { + try { + let timeout1; + timeout1 = ms === undefined ? appConst.longTimeout : ms; + let message = 'Spinner still displayed! timeout is ' + timeout1; + return await this.browser.waitUntil(async () => { + let res = await this.isElementNotDisplayed("//div[@class='spinner']"); + return res; + }, {timeout: timeout1, timeoutMsg: message}); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_spinner'); + throw new Error(` Spinner error, screenshot :${screenshot} ` + err); + } } waitUntilElementNotVisible(selector, ms) { @@ -295,10 +301,9 @@ class Page { }, {timeout: ms, timeoutMsg: message}); } - isElementNotDisplayed(selector) { - return this.getDisplayedElements(selector).then(result => { - return result.length === 0; - }) + async isElementNotDisplayed(selector) { + let result = await this.getDisplayedElements(selector); + return result.length === 0; } async getAttribute(selector, attributeName) { @@ -306,6 +311,13 @@ class Page { return await element.getAttribute(attributeName); } + async waitForAttributeIsPresent(elementLocator, attribute) { + await this.getBrowser().waitUntil(async () => { + let text = await this.getAttribute(elementLocator, attribute); + return text != null; + }, {timeout: appConst.shortTimeout, timeoutMsg: `Expected attribute ${attribute} is not set in the element ${elementLocator}`}); + } + async removeNotificationMessage() { try { let selector = "//div[contains(@id,'NotificationContainer')]//span[contains(@class,'notification-remove')]"; @@ -549,6 +561,7 @@ class Page { }, {timeout: appConst.mediumTimeout, timeoutMsg: "Class should contain 'invalid' "}); } + // checks the attribute value (actual value contains expected value) waitForAttributeHasValue(selector, attribute, value) { return this.getBrowser().waitUntil(() => { return this.getAttribute(selector, attribute).then(result => { @@ -610,6 +623,22 @@ class Page { acceptAlert() { return this.getBrowser().acceptAlert(); } + + async waitForLangAttribute(lang) { + let locator = "//html"; + await this.getBrowser().waitUntil(async () => { + let text = await this.getAttribute(locator, "lang"); + return text.includes(lang); + }, {timeout: appConst.shortTimeout, timeoutMsg: "Html tag should contain 'lang' attribute"}); + } + + // checks the attribute value (actual value === expected value) + async waitForAttributeValue(locator, attrName, expectedValue) { + await this.getBrowser().waitUntil(async () => { + let text = await this.getAttribute(locator, attrName); + return text === expectedValue; + }, {timeout: appConst.mediumTimeout, timeoutMsg: `Expected attribute ${attrName} is not set in the element ${locator}`}); + } } module.exports = Page; diff --git a/testing/page_objects/project/layers.content.tree.dialog.js b/testing/page_objects/project/layers.content.tree.dialog.js index f9162120..845c5249 100644 --- a/testing/page_objects/project/layers.content.tree.dialog.js +++ b/testing/page_objects/project/layers.content.tree.dialog.js @@ -26,19 +26,17 @@ class LayersContentTreeDialog extends Page { await this.clickOnElement(this.cancelButtonTop); return await this.waitForDialogClosed(); } catch (err) { - await this.saveScreenshot('err_layers_tree_click_on_cancel_button'); + this.saveScreenshot('err_layers_tree_click_on_cancel_button'); throw new Error('Layers Content Tree dialog, error when clicking on Cancel(Top) button ' + err); } } - async waitForDialogLoaded() { - try { - let selector = XPATH.container + XPATH.layersTreeList; - await this.waitForElementDisplayed(selector, appConst.shortTimeout) - } catch (err) { - let screenshot = await this.saveScreenshotUniqueName('err_open_layers_tree_dialog'); - throw new Error('Layers Content Tree dialog dialog should be opened!, screenshot:' + screenshot + ' ' + err); - } + waitForDialogLoaded() { + let selector = XPATH.container + XPATH.layersTreeList; + return this.waitForElementDisplayed(selector, appConst.shortTimeout).catch(err => { + this.saveScreenshot('err_open_layers_tree_dialog'); + throw new Error('Layers Content Tree dialog dialog should be opened!' + err); + }); } isDialogLoaded() { @@ -49,8 +47,7 @@ class LayersContentTreeDialog extends Page { try { return await this.waitForElementNotDisplayed(XPATH.container, appConst.shortTimeout); } catch (err) { - let screenshot = await this.saveScreenshotUniqueName('err_dialog_close'); - throw new Error("Layers Content Tree dialog should be closed , screenshot : " + screenshot + ' ' + err); + throw new Error("Layers Content Tree dialog should be closed " + err); } } @@ -86,11 +83,6 @@ class LayersContentTreeDialog extends Page { await this.waitForElementDisplayed(buttonLocator, appConst.mediumTimeout); return await this.getText(buttonLocator + "//span"); } - - async clickOnLayerItem(layerName) { - - } } - module.exports = LayersContentTreeDialog; diff --git a/testing/page_objects/project/project-wizard-dialog/project.wizard.access.mode.step.js b/testing/page_objects/project/project-wizard-dialog/project.wizard.access.mode.step.js index ffd3a8de..dc4b3111 100644 --- a/testing/page_objects/project/project-wizard-dialog/project.wizard.access.mode.step.js +++ b/testing/page_objects/project/project-wizard-dialog/project.wizard.access.mode.step.js @@ -3,7 +3,7 @@ */ const appConst = require('../../../libs/app_const'); const ProjectWizardDialog = require('./project.wizard.dialog'); -const ComboBox = require('../../components/loader.combobox'); +const ExtendedPrincipalComboBox = require('../../components/projects/extended.principal.combobox'); const XPATH = { container: "//div[contains(@id,'ProjectWizardDialog')]", @@ -21,7 +21,6 @@ class ProjectWizardDialogAccessModeStep extends ProjectWizardDialog { await this.pause(200); return await this.clickOnElement(selector); } - async waitForLoaded() { await this.getBrowser().waitUntil(async () => { let actualDescription = await this.getStepDescription(); @@ -30,8 +29,8 @@ class ProjectWizardDialogAccessModeStep extends ProjectWizardDialog { } async selectUserInCustomReadAccessSelector(principalDisplayName) { - let comboBox = new ComboBox(); - await comboBox.typeTextAndSelectOption(principalDisplayName, XPATH.projectReadAccessWizardStepForm); + let extendedPrincipalComboBox = new ExtendedPrincipalComboBox(); + await extendedPrincipalComboBox.clickOnFilteredByDisplayNameUserAndClickOnApply(principalDisplayName, XPATH.container); console.log("Project Wizard, principal is selected: " + principalDisplayName); return await this.pause(300); } diff --git a/testing/page_objects/project/project-wizard-dialog/project.wizard.dialog.js b/testing/page_objects/project/project-wizard-dialog/project.wizard.dialog.js index a706c9d5..c5e82bc5 100644 --- a/testing/page_objects/project/project-wizard-dialog/project.wizard.dialog.js +++ b/testing/page_objects/project/project-wizard-dialog/project.wizard.dialog.js @@ -10,9 +10,6 @@ const XPATH = { title: "//h6[@class='xp-admin-common-main-name']", stepDescription: "//p[@class='xp-admin-common-sub-name']", buttonRow: "//div[contains(@class,'button-container')]", - nextButton: "//button[contains(@id,'DialogButton') and child::span[text()='Next']]", - backButton: "//button[contains(@id,'DialogButton') and child::span[text()='Back']]", - skipButton: "//button[contains(@id,'DialogButton') and child::span[text()='Skip']]", copyFromParentButton: parent => `//button[contains(@id,'Button') and child::span[text()='Copy from ${parent}']]`, }; @@ -22,20 +19,16 @@ class ProjectWizardDialog extends Page { return XPATH.container + lib.CANCEL_BUTTON_TOP; } - get copyFromParentButton() { - return XPATH.container + XPATH.copyFromParentButton; - } - get nextButton() { - return XPATH.container + XPATH.nextButton; + return XPATH.container + lib.dialogButton('Next'); } get backButton() { - return XPATH.container + XPATH.backButton; + return XPATH.container + lib.dialogButton('Back'); } get skipButton() { - return XPATH.container + XPATH.skipButton; + return XPATH.container + lib.dialogButton('Skip'); } async waitForSkipButtonDisplayed() { @@ -47,9 +40,10 @@ class ProjectWizardDialog extends Page { } } - async waitForCopyFromParentButtonNotDisplayed() { + async waitForCopyFromParentButtonNotDisplayed(parent) { try { - return await this.waitForElementNotDisplayed(this.copyFromParentButton, appConst.mediumTimeout); + let locator = XPATH.container + XPATH.copyFromParentButton(parent) + return await this.waitForElementNotDisplayed(locator, appConst.mediumTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_copy_from_parent_button'); throw new Error('Copy from parent button is displayed: screenshot ' + screenshot + " " + err); @@ -115,10 +109,14 @@ class ProjectWizardDialog extends Page { } async clickOnSkipButton() { - await this.waitForSkipButtonDisplayed(); - await this.waitForSkipButtonEnabled(); - await this.clickOnElement(this.skipButton); - return await this.pause(300); + try { + await this.waitForSkipButtonDisplayed(); + await this.waitForSkipButtonEnabled(); + await this.clickOnElement(this.skipButton); + return await this.pause(300); + } catch (err) { + throw new Error("Error occurred during clicking on Skip button: " + err); + } } async waitForNextButtonDisplayed() { @@ -149,11 +147,15 @@ class ProjectWizardDialog extends Page { } async clickOnNextButton() { - await this.waitForNextButtonDisplayed(); - await this.waitForNextButtonEnabled(); - await this.pause(500); - await this.clickOnElement(this.nextButton); - return await this.pause(300); + try { + await this.waitForNextButtonDisplayed(); + await this.waitForNextButtonEnabled(); + await this.pause(500); + await this.clickOnElement(this.nextButton); + return await this.pause(300); + } catch (err) { + throw new Error("Error occurred during clicking on Next button: " + err); + } } async waitForBackButtonDisplayed() { @@ -171,7 +173,7 @@ class ProjectWizardDialog extends Page { return await this.waitForDialogClosed(); } catch (err) { await this.saveScreenshot(appConst.generateRandomName('err_cancel_button')); - throw new Error('Layers Content Tree dialog, error when clicking on Cancel(Top) button ' + err); + throw new Error('Project Wizard dialog, error when clicking on Cancel(Top) button ' + err); } } @@ -180,7 +182,7 @@ class ProjectWizardDialog extends Page { return await this.waitForElementNotDisplayed(XPATH.container, appConst.saveProjectTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_wizard_not_closed'); - throw new Error('Layers Content Tree dialog should be closed, screenshot ' + screenshot + ' ' + err); + throw new Error('Project Wizard dialog should be closed, screenshot ' + screenshot + ' ' + err); } } @@ -188,7 +190,7 @@ class ProjectWizardDialog extends Page { try { return await this.waitForElementDisplayed(this.cancelButtonTop, appConst.shortTimeout); } catch (err) { - throw new Error('Layers Content Tree dialog dialog - Cancel button is not displayed :' + err); + throw new Error('Project Wizard dialog - Cancel button is not displayed :' + err); } } @@ -197,6 +199,7 @@ class ProjectWizardDialog extends Page { } async getStepDescription() { + await this.waitForElementDisplayed(XPATH.container + XPATH.stepDescription, appConst.mediumTimeout); return await this.getText(XPATH.container + XPATH.stepDescription); } diff --git a/testing/page_objects/project/project-wizard-dialog/project.wizard.language.step.js b/testing/page_objects/project/project-wizard-dialog/project.wizard.language.step.js index d6d7188e..a8ec6ab7 100644 --- a/testing/page_objects/project/project-wizard-dialog/project.wizard.language.step.js +++ b/testing/page_objects/project/project-wizard-dialog/project.wizard.language.step.js @@ -41,7 +41,7 @@ class ProjectWizardDialogLanguageStep extends ProjectWizardDialog { async selectLanguage(language) { let localeComboBox = new LocaleComboBox(); - await localeComboBox.clickOnFilteredLanguageAndClickOnOk(language, XPATH.localeStep); + await localeComboBox.clickOnFilteredLanguage(language, XPATH.localeStep); console.log("Project Wizard, language is selected: " + language); return await this.pause(300); } diff --git a/testing/page_objects/project/project-wizard-dialog/project.wizard.parent.project.step.js b/testing/page_objects/project/project-wizard-dialog/project.wizard.parent.project.step.js index ceb2778e..6d8ab67c 100644 --- a/testing/page_objects/project/project-wizard-dialog/project.wizard.parent.project.step.js +++ b/testing/page_objects/project/project-wizard-dialog/project.wizard.parent.project.step.js @@ -29,30 +29,47 @@ class ProjectWizardDialogParentProjectStep extends ProjectWizardDialog { async selectParentParentProjects(names) { for (let name of names) { - await this.selectParentProject(name); + await this.selectParentProjectMulti(name); } } + // Type a text (description) in the filter input then click on filtered item then click on 'OK' button and apply selection + async typeTextInOptionFilterInputAndSelectOption(text, projectDisplayName) { + let projectsComboBox = new ProjectsComboBox(); + await this.typeTextInInput(this.projectOptionsFilterInput, text); + await projectsComboBox.clickOnFilteredByDisplayNameItem(projectDisplayName, XPATH.container); + return await this.pause(400); + } + + // Type a name (description) in the filter input then click on filtered item then click on OK button and apply selection async selectParentProject(projectDisplayName) { let projectsComboBox = new ProjectsComboBox(); - await projectsComboBox.selectFilteredByDisplayNameAndClickOnOk(projectDisplayName); + await projectsComboBox.selectFilteredByDisplayName(projectDisplayName); + console.log("Project Wizard, parent project is selected: " + projectDisplayName); + return await this.pause(400); + } + + async selectParentProjectMulti(projectDisplayName) { + let projectsComboBox = new ProjectsComboBox(); + await projectsComboBox.selectFilteredByDisplayNameAndClickOnApply(projectDisplayName); console.log("Project Wizard, parent project is selected: " + projectDisplayName); return await this.pause(400); } async selectParentProjectById(projectId) { let projectsComboBox = new ProjectsComboBox(); - await projectsComboBox.selectFilteredByIdAndClickOnOk(projectId); + await projectsComboBox.selectFilteredByIdAndClickOnApply(projectId); return await this.pause(400); } async getSelectedProjects() { try { let locator = XPATH.container + XPATH.projectSelectedOptionView + lib.H6_DISPLAY_NAME; + await this.pause(1000); return await this.getTextInDisplayedElements(locator); } catch (err) { - let screenshot = await this.saveScreenshotUniqueName('err_proj_parent_step'); - throw new Error("Project Wizard, parent step, screenshot: " + screenshot + " " + err); + let screenshot = await this.saveScreenshotUniqueName('err_proj_parent_step_selected_tems'); + throw new Error(`Project Wizard, parent step, screenshot:${screenshot} ` + err); } } @@ -66,7 +83,7 @@ class ProjectWizardDialogParentProjectStep extends ProjectWizardDialog { try { let projectsComboBox = new ProjectsComboBox(); let optionLocator = projectsComboBox.buildLocatorForOptionByDisplayName(projectDisplayName, XPATH.container); - await projectsComboBox.selectFilteredByDisplayNameAndClickOnOk(optionLocator); + await projectsComboBox.selectFilteredByDisplayNameAndClickOnApply(optionLocator); return await this.pause(400); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('parent_proj_combobox'); @@ -74,21 +91,22 @@ class ProjectWizardDialogParentProjectStep extends ProjectWizardDialog { } } - // Clicks on OK button in the Projects Combobox: - async clickOnOKButtonInProjectsDropdown() { + // Clicks on Apply button in the Projects Combobox: + async clickOnApplyButtonInProjectsDropdown() { try { let projectsComboBox = new ProjectsComboBox(); return await projectsComboBox.clickOnApplySelectionButton(); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('parent_proj_combobox'); - throw new Error("Error occurred in Projects Combobox, screenshot:" + screenshot + ' ' + err); + throw new Error(`Error occurred in Projects Combobox, screenshot:${screenshot} ` + err); } } - async clickOnRemoveSelectedProjectIcon() { - let locator = XPATH.container + XPATH.projectSelectedOptionView + lib.REMOVE_ICON; + async clickOnRemoveSelectedProjectIcon(displayName) { + let locator = XPATH.container + XPATH.projectSelectedOptionView + lib.itemByDisplayName(displayName) + '/../..' + lib.REMOVE_ICON; await this.waitForElementDisplayed(locator, appConst.mediumTimeout); await this.clickOnElement(locator); + await this.pause(300); } async getSelectedProject() { diff --git a/testing/page_objects/project/project-wizard-dialog/project.wizard.permissions.step.js b/testing/page_objects/project/project-wizard-dialog/project.wizard.permissions.step.js index bbf5615e..11d2e4ec 100644 --- a/testing/page_objects/project/project-wizard-dialog/project.wizard.permissions.step.js +++ b/testing/page_objects/project/project-wizard-dialog/project.wizard.permissions.step.js @@ -16,7 +16,7 @@ class ProjectWizardDialogPermissionsStep extends ProjectWizardDialog { // Adds a user with the default role (Contributor) in Roles step form: async selectProjectAccessRole(principalDisplayName) { let projectAccessControlComboBox = new ProjectAccessControlComboBox(); - await projectAccessControlComboBox.clickOnFilteredByDisplayNamePrincipalAndClickOnOk(principalDisplayName, XPATH.container); + await projectAccessControlComboBox.clickOnFilteredByDisplayNamePrincipalAndClickOnApply(principalDisplayName, XPATH.container); } addPrincipalsInRolesForm(memberDisplayNames) { diff --git a/testing/page_objects/project/project.wizard.panel.js b/testing/page_objects/project/project.wizard.panel.js index 7d2c99fe..0b79faee 100644 --- a/testing/page_objects/project/project.wizard.panel.js +++ b/testing/page_objects/project/project.wizard.panel.js @@ -1,16 +1,18 @@ const Page = require('../page'); const lib = require('../../libs/elements'); const appConst = require('../../libs/app_const'); -const ComboBox = require('../components/loader.combobox'); +const ProjectApplicationsComboBox = require('../components/projects/project.applications.combobox'); +const ProjectAccessControlComboBox = require('../components/projects/project.access.control.combobox'); +const LocaleSelectorDropdown = require('../components/selectors/locale.selector.dropdown'); +const ExtendedPrincipalComboBox = require('../components/projects/extended.principal.combobox'); const XPATH = { settingsContainer: "//div[contains(@id,'ContentAppBar')]", container: `//div[contains(@id,'ProjectWizardPanel')]`, displayNameInput: `//input[contains(@name,'displayName')]`, + projectSelectedOptionViewDiv: "//div[contains(@id,'ProjectSelectedOptionView')]", tabTitle: "//li[contains(@id,'AppBarTabMenuItem')]", toolbar: `//div[contains(@id,'Toolbar')]`, - saveButton: `//button[contains(@id,'ActionButton') and child::span[text()='Save']]`, - deleteButton: `//button[contains(@id,'ActionButton') and child::span[text()='Delete']]`, selectedProjectAccessOptions: "//div[contains(@id,'ProjectACESelectedOptionsView')]", selectedReadAccessOptions: "//div[contains(@id,'PrincipalSelectedOptionsView')]", selectedReadAccessOption: "//div[contains(@id,'PrincipalSelectedOptionView')]", @@ -28,16 +30,18 @@ const XPATH = { `//span[contains(@id,'RadioButton') and descendant::label[contains(.,'${descr}')]]`, wizardStepByTitle: name => `//ul[contains(@id,'WizardStepNavigator')]//li[contains(@id,'TabBarItem') and @title='${name}']`, - aclEntryByName: name => `//div[contains(@id,ProjectAccessControlEntryView) and descendant::h6[contains(@class,'main-name') and contains(.,'${name}')]]` + aclEntryByName: name => `//div[contains(@id,ProjectAccessControlEntryView) and descendant::h6[contains(@class,'main-name') and contains(.,'${name}')]]`, + projectApplicationSelectedOptionByName: appName => `//div[contains(@id,'ProjectApplicationSelectedOptionView') and descendant::h6[contains(@class,'main-name') and contains(.,'${appName}')] ]`, }; class ProjectWizardPanel extends Page { - get projectIdentifierInput() { - return XPATH.container + lib.formItemByLabel("Identifier") + lib.TEXT_INPUT; + + get toolbar() { + return XPATH.toolbar; } - get projectIdentifierValidationMessage() { - return XPATH.container + lib.formItemByLabel("Identifier") + "//div[contains(@id,'ValidationRecordingViewer')]//li"; + get projectIdentifierInput() { + return XPATH.container + lib.formItemByLabel('Identifier') + lib.TEXT_INPUT; } get displayNameInput() { @@ -49,27 +53,27 @@ class ProjectWizardPanel extends Page { } get customReadAccessOptionsFilterInput() { - return XPATH.projectReadAccessWizardStepForm + XPATH.accessFormItem + lib.COMBO_BOX_OPTION_FILTER_INPUT; + return XPATH.projectReadAccessWizardStepForm + XPATH.accessFormItem + lib.DROPDOWN_SELECTOR.OPTION_FILTER_INPUT; } get localeOptionsFilterInput() { - return XPATH.container + XPATH.localeComboBoxDiv + lib.COMBO_BOX_OPTION_FILTER_INPUT; + return XPATH.container + XPATH.localeComboBoxDiv + lib.DROPDOWN_SELECTOR.OPTION_FILTER_INPUT; } get projectApplicationsOptionsFilterInput() { - return XPATH.container + XPATH.projectApplicationsComboboxDiv + lib.COMBO_BOX_OPTION_FILTER_INPUT; + return XPATH.container + XPATH.projectApplicationsComboboxDiv + lib.DROPDOWN_SELECTOR.OPTION_FILTER_INPUT; } get saveButton() { - return XPATH.container + XPATH.toolbar + XPATH.saveButton; + return XPATH.container + XPATH.toolbar + lib.actionButtonStrict('Save'); } get deleteButton() { - return XPATH.container + XPATH.toolbar + XPATH.deleteButton; + return XPATH.container + XPATH.toolbar + lib.actionButtonStrict('Delete'); } get descriptionInput() { - return XPATH.container + lib.formItemByLabel("Description") + lib.TEXT_INPUT; + return XPATH.container + lib.formItemByLabel('Description') + lib.TEXT_INPUT; } get selectedCustomReadAccessOptions() { @@ -92,26 +96,31 @@ class ProjectWizardPanel extends Page { return this.isClickable(this.localeOptionsFilterInput); } - async waitAndClickOnSave() { - await this.waitForSaveButtonEnabled(); - await this.clickOnElement(this.saveButton); - return await this.pause(1000); + async isProjectSelectorDisabled() { + let locator = XPATH.container + "//div[contains(@id, 'ProjectsSelector')]"; + let classAttr = await this.getAttribute(locator, 'class'); + return classAttr.includes('disabled'); } - async getProjectIdentifierValidationMessage() { - await this.waitForElementDisplayed(this.projectIdentifierValidationMessage, appConst.shortTimeout); - return await this.getText(this.projectIdentifierValidationMessage); + async getSelectedParentProjectsDisplayName() { + let locator = XPATH.container + XPATH.projectSelectedOptionViewDiv + lib.H6_DISPLAY_NAME; + await this.waitForElementDisplayed(locator, appConst.mediumTimeout); + return await this.getTextInDisplayedElements(locator); } - async waitForProjectIdentifierValidationMessageNotVisible() { - return await this.waitForElementNotDisplayed(this.projectIdentifierValidationMessage, appConst.shortTimeout); + async waitAndClickOnSave() { + await this.waitForSaveButtonEnabled(); + await this.clickOnElement(this.saveButton); + return await this.pause(1000); } - waitForLoaded() { - return this.waitForElementDisplayed(this.descriptionInput, appConst.shortTimeout).catch(err => { - this.saveScreenshot('err_open_insert_anchor_dialog'); - throw new Error('Project Wizard was not loaded!' + err); - }); + async waitForLoaded() { + try { + await this.waitForElementDisplayed(this.descriptionInput, appConst.shortTimeout) + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_project_wizard'); + throw new Error(`Project Wizard was not loaded! screenshot: ${screenshot} ` + err); + } } waitForWizardClosed() { @@ -135,25 +144,21 @@ class ProjectWizardPanel extends Page { let result = await this.getDisplayedElements(this.saveButton); if (result.length === 0) { await this.saveScreenshot('err_pr_wizard'); - throw new Error('Save button is not disabled!'); + throw new Error('Save button is not displayed!'); } return await this.waitForElementDisabled(this.saveButton, appConst.mediumTimeout); } catch (err) { - await this.saveScreenshot('err_pr_wizard_save_btn'); - throw new Error("Save button is not disabled :" + err); + let screenshot = await this.saveScreenshotUniqueName('err_pr_wizard_save_btn'); + throw new Error(`Project Wizard Panel - Save button, screenshot :${screenshot} ` + err); } } async waitForDeleteButtonDisabled() { try { - let result = await this.getDisplayedElements(this.deleteButton); - if (result.length === 0) { - await this.saveScreenshot('err_pr_wizard_delete_btn'); - throw new Error('Delete button is not disabled!'); - } return await this.waitForElementDisabled(this.deleteButton, appConst.mediumTimeout); } catch (err) { - throw new Error('Delete button is not disabled :' + err); + let screenshot = await this.saveScreenshotUniqueName('err_pr_wizard_delete_btn'); + throw new Error(`Delete button is not disabled, screenshot :${screenshot} ` + err); } } @@ -161,7 +166,8 @@ class ProjectWizardPanel extends Page { try { return await this.waitForElementEnabled(this.deleteButton, appConst.longTimeout); } catch (err) { - throw new Error("Delete button is not enabled :" + err); + let screenshot = await this.saveScreenshotUniqueName('err_pr_wizard_delete_btn'); + throw new Error(`Delete button is not enabled, screenshot: ${screenshot} ` + err); } } @@ -188,9 +194,8 @@ class ProjectWizardPanel extends Page { await this.waitForElementDisplayed(selector, appConst.shortTimeout); return await this.getText(selector); } catch (err) { - let screenshot = appConst.generateRandomName('err_project_locale'); - await this.saveScreenshot(screenshot); - throw new Error('Selected language was not found, screenshot: ' + screenshot + ' ' + err); + let screenshot = await this.saveScreenshotUniqueName('err_project_locale'); + throw new Error(`Selected language was not found, screenshot: ${screenshot} ` + err); } } @@ -198,17 +203,11 @@ class ProjectWizardPanel extends Page { return this.waitForElementDisabled(this.projectIdentifierInput, appConst.mediumTimeout); } - waitForProjectIdentifierInputEnabled() { - return this.waitForElementEnabled(this.projectIdentifierInput, appConst.shortTimeout); - } - - async typeInProjectIdentifier(identifier) { - await this.waitForElementDisplayed(this.projectIdentifierInput); - await this.clearInputText(this.projectIdentifierInput); - return await this.typeTextInInput(this.projectIdentifierInput, identifier); + waitForDescriptionInputDisplayed() { + return this.waitForElementDisplayed(XPATH.container, appConst.shortTimeout); } - waitForDescriptionInputDisplayed() { + waitForLanguageDropdownDisplayed() { return this.waitForElementDisplayed(XPATH.container, appConst.shortTimeout); } @@ -217,18 +216,14 @@ class ProjectWizardPanel extends Page { return result.includes('no-modify-permissions'); } - waitForProjectIdentifierInputDisplayed() { - return this.waitForElementDisplayed(this.projectIdentifierInput, appConst.shortTimeout); - } - waitForRolesComboboxDisplayed() { return this.waitForElementDisplayed(this.rolesComboBox); } - //Adds a user with the default role (Contributor) in Roles step form: + // Adds a user with the default role (Contributor) in Roles step form: async selectProjectAccessRoles(principalDisplayName) { - let comboBox = new ComboBox(); - await comboBox.typeTextAndSelectOption(principalDisplayName, XPATH.container + XPATH.projectAccessControlComboBox); + let projectAccessControlComboBox = new ProjectAccessControlComboBox(); + await projectAccessControlComboBox.clickOnFilteredByDisplayNamePrincipalAndClickOnApply(principalDisplayName, XPATH.container); console.log('Project Wizard, principal is selected: ' + principalDisplayName); return await this.pause(1000); } @@ -249,6 +244,7 @@ class ProjectWizardPanel extends Page { return await this.pause(500); } + // Roles dropdown selector - gets all names in ACL-entries in selected options: async getSelectedProjectAccessItems() { let selector = XPATH.container + XPATH.selectedProjectAccessOptions + lib.H6_DISPLAY_NAME; let isDisplayed = await this.isElementDisplayed(XPATH.container + XPATH.selectedProjectAccessOptions); @@ -259,6 +255,7 @@ class ProjectWizardPanel extends Page { } } + // Gets user's role(Owner, Contributor..) in selected option in Roles-dropdown async getSelectedProjectAccessRole(userName) { let selector = XPATH.container + XPATH.aclEntryByName(userName) + XPATH.projectAccessSelectorTabMenu; let isDisplayed = await this.isElementDisplayed(selector); @@ -276,21 +273,22 @@ class ProjectWizardPanel extends Page { await this.clickOnElement(selector); return await this.pause(300); } catch (err) { - this.saveScreenshot('err_remove_access_entry'); + await this.saveScreenshot('err_remove_access_entry'); throw new Error('Error when trying to remove project Access Item ' + err); } } async selectUserInCustomReadAccess(principalDisplayName) { - let comboBox = new ComboBox(); - await comboBox.typeTextAndSelectOption(principalDisplayName, XPATH.projectReadAccessWizardStepForm); + let extendedPrincipalComboBox = new ExtendedPrincipalComboBox(); + await extendedPrincipalComboBox.clickOnFilteredByDisplayNameUserAndClickOnApply(principalDisplayName, + XPATH.projectReadAccessWizardStepForm); console.log('Project Wizard, principal is selected: ' + principalDisplayName); return await this.pause(300); } async selectLanguage(language) { - let comboBox = new ComboBox(); - await comboBox.typeTextAndSelectOption(language, XPATH.projectReadAccessWizardStepForm + XPATH.localeComboBoxDiv); + let localeSelectorDropdown = new LocaleSelectorDropdown(); + await localeSelectorDropdown.clickOnFilteredLanguage(language); console.log('Project Wizard, language is selected: ' + language); return await this.pause(300); } @@ -313,7 +311,7 @@ class ProjectWizardPanel extends Page { return this.getBrowser().keys(['Alt', 'w']); } - //Click on radio button and selects 'Access mode' + // Click on radio button and selects 'Access mode' async clickOnAccessModeRadio(mode) { let selector = XPATH.radioButtonByDescription(mode) + "/input[@type='radio']"; await this.waitForElementEnabled(XPATH.radioButtonByDescription(mode), appConst.shortTimeout); @@ -389,33 +387,32 @@ class ProjectWizardPanel extends Page { await this.clickOnElement(this.removeLanguageButton); return await this.pause(500); } catch (err) { - let screenshot = appConst.generateRandomName('err_project_remove_icon'); - await this.saveScreenshot(screenshot); - throw new Error(`Error during clicking on remove language icon, screenshot: ${screenshot} ` + err); + let screenshot = await this.saveScreenshotUniqueName('err_project_remove_icon'); + throw new Error(`Error occurred after clicking on remove language icon, screenshot: ${screenshot} ` + err); } } - async waitForDisplayNameInputFocused() { - let message = 'Display Name input is not focused' + appConst.mediumTimeout; - await this.getBrowser().waitUntil(async () => { - return await this.isFocused(this.displayNameInput); - }, {timeout: appConst.mediumTimeout, timeoutMsg: message}); - } - waitForProjectApplicationsOptionsFilterInputDisplayed() { return this.waitForElementDisplayed(this.projectApplicationsOptionsFilterInput, appConst.mediumTimeout); } + waitForLanguageOptionsFilterInputDisplayed() { + return this.waitForElementDisplayed(this.localeOptionsFilterInput, appConst.mediumTimeout); + } + + waitForLanguageOptionsFilterInputNotDisplayed() { + return this.waitForElementNotDisplayed(this.localeOptionsFilterInput, appConst.mediumTimeout); + } + async selectApplication(appName) { try { - let comboBox = new ComboBox(); - await this.waitForProjectApplicationsOptionsFilterInputDisplayed(); - await comboBox.typeTextAndSelectOption(appName, XPATH.projectApplicationsComboboxDiv); + let projectApplicationsComboBox = new ProjectApplicationsComboBox(); + //await this.waitForProjectApplicationsOptionsFilterInputDisplayed(); + await projectApplicationsComboBox.clickFilteredByAppNameItemAndClickOnOk(appName, XPATH.container); console.log('Project Wizard, application is selected: ' + appName); return await this.pause(300); } catch (err) { - let screenshot = appConst.generateRandomName('err_project_wizard'); - await this.saveScreenshot(screenshot); + let screenshot = await this.saveScreenshotUniqueName('err_project_wizard'); throw new Error(`Error during selecting application, screenshot: ${screenshot} ` + err); } } @@ -426,30 +423,60 @@ class ProjectWizardPanel extends Page { await this.waitForElementDisplayed(locator, appConst.shortTimeout); return await this.getTextInDisplayedElements(locator); } catch (err) { - let screenshot = appConst.generateRandomName('err_project_apps'); - await this.saveScreenshot(screenshot); + let screenshot = await this.saveScreenshotUniqueName('err_project_apps'); throw new Error(`Project apps were not found, screenshot: ${screenshot} ` + err); } } - async clickOnRemoveApplicationIcon() { + async waitForRemoveAppIconNotDisplayed(appName) { try { - let locator = XPATH.container + "//div[contains(@id,'ProjectApplicationSelectedOptionView')]" + lib.REMOVE_ICON - await this.waitForElementDisplayed(locator, appConst.mediumTimeout); - await this.clickOnElement(locator); + let removeIconLocator = XPATH.container + XPATH.projectApplicationSelectedOptionByName(appName) + lib.REMOVE_ICON; + await this.waitForElementNotDisplayed(removeIconLocator, appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_proj_wizard_page_remove_icon'); + throw new Error("Project wizard page - 'remove app' icon should not be displayed, screenshot: " + screenshot + ' ' + err); + } + } + + async waitForRemoveAppIconDisplayed(appName) { + try { + let removeIconLocator = XPATH.container + XPATH.projectApplicationSelectedOptionByName(appName) + lib.REMOVE_ICON; + await this.waitForElementDisplayed(removeIconLocator, appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_proj_wizard_page_remove_icon'); + throw new Error("Project wizard page - 'remove app' icon should be displayed, screenshot: " + screenshot + ' ' + err); + } + } + + async clickOnRemoveApplicationIcon(appName) { + try { + let removeIcon = XPATH.container + XPATH.projectApplicationSelectedOptionByName(appName) + lib.REMOVE_ICON; + await this.waitForElementDisplayed(removeIcon, appConst.mediumTimeout); + await this.clickOnElement(removeIcon); return await this.pause(500); } catch (err) { - let screenshot = appConst.generateRandomName('err_project_remove_icon'); - await this.saveScreenshot(screenshot); + let screenshot = await this.saveScreenshotUniqueName('err_project_remove_icon'); throw new Error('Error during clicking on remove application icon, screenshot: ' + screenshot + " " + err); } } async clickOnEditProjectConfig(appName) { - let locator = XPATH.container + lib.selectedProjectView(appName) + lib.EDIT_ICON; + let locator = XPATH.container + lib.PROJECTS.selectedProjectView(appName) + lib.EDIT_ICON; await this.waitForElementDisplayed(locator, appConst.mediumTimeout); await this.clickOnElement(locator); } + + // check for Accessibility attributes: wizard-toolbar role + async waitForToolbarRoleAttribute(expectedRole) { + let locator = XPATH.container + XPATH.toolbar; + await this.waitForAttributeValue(locator, 'role', expectedRole, appConst.shortTimeout); + } + + // check for Accessibility attributes: wizard-toolbar aria-label: + async waitForToolbarAriaLabelAttribute(expectedValue) { + let locator = XPATH.container + XPATH.toolbar; + await this.waitForAttributeValue(locator, 'aria-label', expectedValue, appConst.shortTimeout); + } } module.exports = ProjectWizardPanel; diff --git a/testing/page_objects/project/settings.browse.panel.js b/testing/page_objects/project/settings.browse.panel.js index 7d7a42c2..1133d756 100644 --- a/testing/page_objects/project/settings.browse.panel.js +++ b/testing/page_objects/project/settings.browse.panel.js @@ -13,22 +13,19 @@ const XPATH = { appBar: "//div[contains(@id,'ContentAppBar')]", appBarTabMenu: "//div[contains(@id,'AppBarTabMenu')]", homeButton: "//div[contains(@class,'home-button') and descendant::span[text()='Settings']]", - toolbar: `//div[contains(@id,'SettingsBrowseToolbar')]`, + toolbarDiv: `//div[contains(@id,'SettingsBrowseToolbar')]`, itemsTreeGrid: `//div[contains(@id,'SettingsItemsTreeGrid')]`, settingsTreeList: `//ul[contains(@id,'SettingsTreeList')]`, - treeGridToolbar: `//div[contains(@id,'TreeGridToolbar')]`, - selectionControllerCheckBox: `//div[contains(@id,'SelectionController')]`, + listBoxToolbarDiv: `//div[contains(@id,'ListBoxToolbar')]`, + listSelectionControllerDiv: `//div[contains(@id,'ListSelectionController')]`, numberInSelectionToggler: `//button[contains(@id,'SelectionPanelToggler')]/span`, showIssuesButton: "//button[contains(@id,'ShowIssuesDialogButton')]//span", contextMenuItemByName: (name) => { return `${lib.TREE_GRID_CONTEXT_MENU}/li[contains(@id,'MenuItem') and contains(.,'${name}')]`; }, - rootFolderByDisplayName: - displayName => `//div[contains(@id,'NamesView') and child::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]`, - projectItemByDisplayName: - displayName => `//div[contains(@id,'NamesView') and descendant::span[contains(@class,'display-name') and contains(.,'${displayName}')]]`, + displayName => `//*[contains(@class,'item-view-wrapper') and descendant::h6[contains(@class,'main-name') and contains(.,'${displayName}')]]`, projectCheckboxByName: name => { @@ -39,9 +36,6 @@ const XPATH = { return `//div[contains(@id,'ProjectItemViewer') and descendant::p[contains(@class,'sub-name') and contains(.,'${id}')]]/..//..//div[contains(@id,'Checkbox')]/label` }, - projectItemByName(name) { - return `//div[contains(@id,'NamesView') and descendant::span[@class='display-name' and contains(.,'${name}')]]` - }, expanderIconByName: name => `${lib.PROJECTS.projectByName(name)}/..//div[contains(@class,'toggle icon-arrow_drop_up')]`, tabCloseIcon: projectDisplayName => XPATH.appBarTabMenu + @@ -50,11 +44,12 @@ const XPATH = { class SettingsBrowsePanel extends BaseBrowsePanel { - get container() { - return XPATH.container; + get toolbar() { + return XPATH.container + XPATH.toolbarDiv; } + get deleteButton() { - return XPATH.toolbar + `/*[contains(@id, 'ActionButton') and child::span[text()='Delete']]`; + return XPATH.toolbarDiv + `/*[contains(@id, 'ActionButton') and child::span[text()='Delete']]`; } get homeButton() { @@ -62,31 +57,35 @@ class SettingsBrowsePanel extends BaseBrowsePanel { } get newButton() { - return XPATH.toolbar + `/*[contains(@id, 'ActionButton') and child::span[text()='New...']]`; + return XPATH.toolbarDiv + `/*[contains(@id, 'ActionButton') and child::span[text()='New...']]`; } get editButton() { - return XPATH.toolbar + `/*[contains(@id, 'ActionButton') and child::span[text()='Edit']]`; + return XPATH.toolbarDiv + `/*[contains(@id, 'ActionButton') and child::span[text()='Edit']]`; } get syncButton() { - return XPATH.toolbar + `/*[contains(@id, 'ActionButton') and child::span[text()='Sync']]`; + return XPATH.toolbarDiv + `/*[contains(@id, 'ActionButton') and child::span[text()='Sync']]`; } get treeGrid() { return XPATH.container + XPATH.settingsTreeList; } + get browseToolbar() { + return XPATH.container + XPATH.toolbarDiv; + } + get selectionControllerCheckBox() { - return XPATH.container + XPATH.treeGridToolbar + XPATH.selectionControllerCheckBox; + return XPATH.container + XPATH.listBoxToolbarDiv + XPATH.listSelectionControllerDiv; } get selectionPanelToggler() { - return `${XPATH.container}${XPATH.treeGridToolbar}${lib.SELECTION_PANEL_TOGGLER}`; + return `${XPATH.container}${XPATH.listBoxToolbarDiv}${lib.SELECTION_PANEL_TOGGLER}`; } get numberInToggler() { - return XPATH.treeGridToolbar + XPATH.numberInSelectionToggler; + return XPATH.listBoxToolbarDiv + XPATH.numberInSelectionToggler; } get displayNames() { @@ -103,7 +102,7 @@ class SettingsBrowsePanel extends BaseBrowsePanel { try { let expanderIcon = XPATH.settingsTreeList + XPATH.expanderIconByName(name); await this.clickOnElement(expanderIcon); - return await this.pause(1100); + return await this.pause(500); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_click_on_expander'); throw new Error(`Error occurred after clicking on expander-icon, screenshot: ${screenshot} ` + err); @@ -112,7 +111,7 @@ class SettingsBrowsePanel extends BaseBrowsePanel { async waitForItemDisplayed(projectName) { try { - let locator = XPATH.settingsTreeList + XPATH.projectItemByName(projectName); + let locator = XPATH.settingsTreeList + XPATH.projectItemByDisplayName(projectName); return await this.waitForElementDisplayed(locator, appConst.mediumTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_browse_panel'); @@ -132,7 +131,7 @@ class SettingsBrowsePanel extends BaseBrowsePanel { async waitForLanguageIconDisplayed(displayName) { try { - let locatorIcon = XPATH.settingsTreeList + lib.PROJECTS.projectNameAndIconViewDiv(displayName) + "//div[contains(@id,'Flag')]"; + let locatorIcon = XPATH.settingsTreeList + lib.PROJECTS.projectByName(displayName) + "//div[contains(@id,'Flag')]"; await this.waitForElementDisplayed(locatorIcon, appConst.longTimeout); return await this.getAttribute(locatorIcon, 'data-code'); } catch (err) { @@ -164,16 +163,18 @@ class SettingsBrowsePanel extends BaseBrowsePanel { return await this.pause(500); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_find_project'); - throw Error('Project Browse Panel - project was not found ' + screenshot + ' ' + err); + throw new Error('Project Browse Panel - project was not found ' + screenshot + ' ' + err); } } - waitForItemByNameVisible(name) { + async waitForItemByNameVisible(name) { let nameXpath = XPATH.settingsTreeList + lib.itemByName(name); - return this.waitForElementDisplayed(nameXpath, appConst.mediumTimeout).catch(err => { - this.saveScreenshot('err_find_' + name); - throw Error('Row with the name ' + name + ' is not visible after ' + appConst.mediumTimeout + 'ms') - }) + try { + await this.waitForElementDisplayed(nameXpath, appConst.mediumTimeout); + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_find_item'); + throw Error(`Row with the name is not displayed! screenshot:${screenshot} ` + err); + } } async waitForProjectByDisplayNameVisible(displayName) { @@ -182,7 +183,7 @@ class SettingsBrowsePanel extends BaseBrowsePanel { return await this.waitForElementDisplayed(nameXpath, appConst.mediumTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_find_project'); - throw new Error('Project is not visible, screenshot:' + screenshot + " " + err); + throw new Error(`Project is not visible, screenshot:${screenshot} ` + err); } } @@ -196,7 +197,7 @@ class SettingsBrowsePanel extends BaseBrowsePanel { return await this.pause(300); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_checkbox_proj'); - throw new Error("Project's checkbox was not found Screenshot:" + screenshot + " " + err); + throw new Error(`Project's checkbox was not found Screenshot:${screenshot} ` + err); } } @@ -214,7 +215,7 @@ class SettingsBrowsePanel extends BaseBrowsePanel { return await this.pause(300); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_checkbox_proj'); - throw new Error("Project's checkbox was not found Screenshot:" + screenshot + " " + err); + throw new Error(`Project's checkbox was not found Screenshot:${screenshot} ` + err); } } @@ -237,56 +238,56 @@ class SettingsBrowsePanel extends BaseBrowsePanel { async rightClickOnProjects() { try { - const nameXpath = XPATH.container + XPATH.rootFolderByDisplayName('Projects'); + const nameXpath = XPATH.container + XPATH.projectItemByDisplayName('Projects') + "//div[contains(@id,'FolderItemViewer')]"; await this.waitForElementDisplayed(nameXpath, appConst.mediumTimeout); return await this.doRightClick(nameXpath); } catch (err) { - await this.saveScreenshotUniqueName("err_rightClick"); - throw Error(`Error occurred after right click on the row:` + err); + await this.saveScreenshotUniqueName('err_rightClick'); + throw new Error(`Error occurred after right click on the row:` + err); } } async rightClickOnProjectItemByDisplayName(displayName) { try { - const nameXpath = XPATH.container + XPATH.projectItemByDisplayName(displayName); + const nameXpath = XPATH.container + XPATH.projectItemByDisplayName(displayName) + "//div[contains(@id,'ProjectItemViewer')]"; await this.waitForElementDisplayed(nameXpath, appConst.mediumTimeout); return await this.doRightClick(nameXpath); } catch (err) { - await this.saveScreenshot(appConst.generateRandomName("err_rightClick")); - throw Error(`Error when do right click on the row:` + err); + let screenshot = await this.saveScreenshotUniqueName('err_rightClick'); + throw new Error(`Error when do right click on the row, screenshot:${screenshot}` + err); } } async openProjectByDisplayName(displayName) { let projectWizard = new ProjectWizard(); // the root folder(Projects) should be expanded: - //1. click on the project: + // 1. click on the project: await this.clickOnRowByDisplayName(displayName); - //2. wait for Edit button gets enabled: + // 2. wait for Edit button gets enabled: await this.clickOnEditButton(); - //3. wait for Project is loaded in the wizard page: + // 3. wait for Project is loaded in the wizard page: return await projectWizard.waitForLoaded(); } async checkAndOpenProjectByDisplayName(displayName) { let projectWizard = new ProjectWizard(); // the root folder(Projects) should be expanded: - //1. check the project: + // 1. check the project: await this.clickOnCheckboxAndSelectRowByName(displayName); - //2. wait for Edit button gets enabled: + // 2. wait for Edit button gets enabled: await this.clickOnEditButton(); - //3. wait for Project is loaded: + // 3. wait for Project is loaded: await projectWizard.waitForLoaded(); return projectWizard; } getProjectDisplayName(name) { - let selector = XPATH.projectItemByName(name) + "//span[@class='display-name']"; + let selector = XPATH.projectItemByDisplayName(name) + "//span[@class='display-name']"; return this.getText(selector) } - getProjectIdentifier(name) { - let selector = XPATH.projectItemByName(name) + "//p[contains(@class,'sub-name')]"; + getProjectIdentifier(displayName) { + let selector = XPATH.projectItemByDisplayName(displayName) + "//p[contains(@class,'sub-name')]"; return this.getText(selector) } @@ -307,11 +308,13 @@ class SettingsBrowsePanel extends BaseBrowsePanel { return await this.getText(XPATH.showIssuesButton); } - waitForSyncButtonEnabled() { - return this.waitForElementEnabled(this.syncButton, appConst.mediumTimeout).catch(err => { - this.saveScreenshot('err_sync_disabled_button'); - throw new Error('Sync button should be enabled, timeout: ' + appConst.mediumTimeout + 'ms') - }) + async waitForSyncButtonEnabled() { + try { + await this.waitForElementEnabled(this.syncButton, appConst.mediumTimeout) + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_sync_disabled_button'); + throw new Error(`Sync button should be enabled, screenshot: ${screenshot} ` + err); + } } async clickOnSyncButton() { @@ -324,23 +327,27 @@ class SettingsBrowsePanel extends BaseBrowsePanel { await this.waitForElementEnabled(this.deleteButton, appConst.shortTimeout); return await this.clickOnElement(this.deleteButton); } catch (err) { - await this.saveScreenshot('err_browsepanel_delete_button'); - throw new Error('Delete button is not enabled! ' + err); + let screenshot = await this.saveScreenshotUniqueName('err_browsepanel_delete_button'); + throw new Error(`Error occurred after clicking on 'Delete' button ! screenshot: ${screenshot} ` + err); } } - waitForDeleteButtonDisabled() { - return this.waitForElementDisabled(this.deleteButton, appConst.mediumTimeout).catch(err => { - this.saveScreenshot('err_delete_disabled_button'); - throw Error('Browse toolbar - Delete button should be disabled, timeout: ' + 3000 + 'ms') - }) + async waitForDeleteButtonDisabled() { + try { + await this.waitForElementDisabled(this.deleteButton, appConst.mediumTimeout) + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_delete_button'); + throw Error(`Delete button is not disabled! screenshot: ${screenshot} ` + err); + } } - waitForDeleteButtonEnabled() { - return this.waitForElementEnabled(this.deleteButton, appConst.mediumTimeout).catch(err => { - this.saveScreenshot('err_delete_button'); - throw new Error('Delete button is not enabled after ' + appConst.mediumTimeout + 'ms') - }) + async waitForDeleteButtonEnabled() { + try { + await this.waitForElementEnabled(this.deleteButton, appConst.mediumTimeout) + } catch (err) { + let screenshot = await this.saveScreenshotUniqueName('err_delete_button'); + throw Error(`Delete button is not enabled! screenshot: ${screenshot} ` + err); + } } } diff --git a/testing/page_objects/publish.report.dialog.js b/testing/page_objects/publish.report.dialog.js index b32eb340..0e919f3a 100644 --- a/testing/page_objects/publish.report.dialog.js +++ b/testing/page_objects/publish.report.dialog.js @@ -15,7 +15,7 @@ const XPATH = { class PublishReportDialog extends Page { get showEntireContentCheckbox() { - return XPATH.container + XPATH.comparisonBlockDiv + lib.SHOW_ENTIRE_CONTENT_CHECKBOX_DIV; + return XPATH.container + XPATH.comparisonBlockDiv + lib.DIV.SHOW_ENTIRE_CONTENT_CHECKBOX_DIV; } get printButton() { @@ -34,7 +34,7 @@ class PublishReportDialog extends Page { return await elements[index].getText(); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_publish_report_comparison_header'); - throw new Error("PublishReport modal dialog, header block, screenshot: " + screenshot + ' ' + err); + throw new Error(`PublishReport modal dialog, header block, screenshot: ${screenshot} ` + err); } } @@ -46,7 +46,7 @@ class PublishReportDialog extends Page { return await elements[index].getText(); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_publish_report_date_subtitle'); - throw new Error("PublishReport modal dialog, subtitle block, screenshot: " + screenshot + ' ' + err); + throw new Error(`PublishReport modal dialog, subtitle block, screenshot: ${screenshot} ` + err); } } @@ -58,7 +58,7 @@ class PublishReportDialog extends Page { return await elements[index].getText(); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_publish_report_date_header'); - throw new Error("PublishReport modal dialog, date in the header block, screenshot: " + screenshot + ' ' + err); + throw new Error(`PublishReport modal dialog, date in the header block, screenshot: ${screenshot} ` + err); } } @@ -69,7 +69,7 @@ class PublishReportDialog extends Page { return await this.getText(locator); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_publish_report_dlg_header'); - throw new Error("PublishReport modal dialog, text in TextAndDate Block, screenshot: " + screenshot + ' ' + err); + throw new Error(`PublishReport modal dialog, text in TextAndDate Block, screenshot: ${screenshot} ` + err); } } @@ -80,12 +80,12 @@ class PublishReportDialog extends Page { return await this.getText(locator); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_publish_report_dlg_date'); - throw new Error("PublishReport modal dialog, date in Comparisons Block, screenshot: " + screenshot + ' ' + err); + throw new Error(`PublishReport modal dialog, date in Comparisons Block, screenshot: ${screenshot} ` + err); } } async waitForShowEntireContentCheckboxNotDisplayed() { - let checkBoxInput = this.showEntireContentCheckbox + lib.CHECKBOX_INPUT; + let checkBoxInput = this.showEntireContentCheckbox + lib.INPUTS.CHECKBOX_INPUT; return await this.waitForElementNotDisplayed(checkBoxInput, appConst.mediumTimeout); } @@ -100,7 +100,7 @@ class PublishReportDialog extends Page { } async isShowEntireContentCheckboxSelected(index) { - let checkBoxInput = this.showEntireContentCheckbox + lib.CHECKBOX_INPUT; + let checkBoxInput = this.showEntireContentCheckbox + lib.INPUTS.CHECKBOX_INPUT; await this.waitForElementDisplayed(this.showEntireContentCheckbox, appConst.mediumTimeout); let res = await this.findElements(checkBoxInput); if (index > res.length) { @@ -122,7 +122,7 @@ class PublishReportDialog extends Page { return await this.waitForElementDisplayed(this.printButton, appConst.mediumTimeout) } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_load_publish_report_dlg'); - throw new Error("PublishReport dialog was not loaded! screenshot: " + screenshot + ' ' + err); + throw new Error(`PublishReport dialog was not loaded! screenshot: ${screenshot} ` + err); } } @@ -132,7 +132,7 @@ class PublishReportDialog extends Page { await this.waitForElementEnabled(this.printButton, appConst.mediumTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_publish_report_print_btn'); - throw new Error("PublishReport modal dialog - Print button, screenshot: " + screenshot + ' ' + err); + throw new Error(`PublishReport modal dialog - Print button, screenshot: ${screenshot} ` + err); } } diff --git a/testing/page_objects/wizardpanel/content.wizard.panel.js b/testing/page_objects/wizardpanel/content.wizard.panel.js index e17b921c..60763197 100644 --- a/testing/page_objects/wizardpanel/content.wizard.panel.js +++ b/testing/page_objects/wizardpanel/content.wizard.panel.js @@ -18,9 +18,12 @@ const WizardDependenciesWidget = require('./details/wizard.dependencies.widget') const PropertiesWidget = require('../browsepanel/detailspanel/properties.widget.itemview'); const EditSettingsDialog = require('../details_panel/edit.settings.dialog'); const PageDescriptorDropdown = require('../components/selectors/page.descriptor.dropdown'); +const WizardLayersWidget = require('../wizardpanel/details/wizard.layers.widget'); +const WizardDetailsPanel = require('../wizardpanel/details/wizard.details.panel'); const XPATH = { container: `//div[contains(@id,'ContentWizardPanel')]`, + projectViewerDiv: `//div[contains(@id,'ProjectViewer')]`, wizardHeader: "//div[contains(@id,'ContentWizardHeader')]", pageEditorTogglerButton: "//button[contains(@id, 'CycleButton') ]", hidePageEditorTogglerButton: "//button[contains(@id,'ContentActionCycleButton') and @title='Hide Page Editor']", @@ -350,7 +353,7 @@ class ContentWizardPanel extends Page { await this.doSwitchToContentBrowsePanel(); return await this.pause(500); } catch (err) { - let screenshot = this.saveScreenshotUniqueName('err_close_wizard'); + let screenshot = await this.saveScreenshotUniqueName('err_close_wizard'); await this.doSwitchToContentBrowsePanel(); throw new Error("Wizard was not closed! screenshot:" + screenshot + ' ' + err); } @@ -398,6 +401,7 @@ class ContentWizardPanel extends Page { async waitForOpened() { try { + let title = await this.getTitle(); await this.waitForElementDisplayed(this.thumbnailUploader, appConst.longTimeout); await this.waitForSpinnerNotVisible(appConst.longTimeout); return await this.pause(200); @@ -490,8 +494,8 @@ class ContentWizardPanel extends Page { await this.waitForSavingButtonNotVisible(); return await this.pause(1200); } catch (err) { - await this.saveScreenshot(appConst.generateRandomName('err_save')); - throw new Error('Error in waitAndClickOnSave: ' + err); + let screenshot = await this.saveScreenshotUniqueName('err_save_content'); + throw new Error(`Error in waitAndClickOnSave: screenshot ${screenshot} ` + err); } } @@ -505,7 +509,7 @@ class ContentWizardPanel extends Page { return await this.clickOnElement(this.archiveButton); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_archive_btn_wizard'); - throw new Error('Error when clicking on Archive button, screenshot: ' + screenshot + ' ' + err); + throw new Error(`Error when clicking on Archive button, screenshot:${screenshot} ` + err); } } @@ -549,7 +553,7 @@ class ContentWizardPanel extends Page { return await this.waitForAttributeHasValue(locator, 'class', 'no-modify-permissions'); } catch (err) { let screenshot = this.saveScreenshotUniqueName('err_readonly_mode'); - throw new Error('Content wizard panel should be in Read only mode! screenshot:' + screenshot + ' ' + err); + throw new Error(`Content wizard panel should be in Read only mode! screenshot:${screenshot} ` + err); } } @@ -661,7 +665,7 @@ class ContentWizardPanel extends Page { await this.waitForElementDisplayed(this.controllerOptionFilterInput, appConst.mediumTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_controller_filter_input'); - throw new Error("Controller selector should be displayed, screenshot:" + screenshot + ' ' + err); + throw new Error(`Controller selector should be displayed, screenshot: ${screenshot} ` + err); } } @@ -670,7 +674,7 @@ class ContentWizardPanel extends Page { await this.waitForElementNotDisplayed(this.controllerOptionFilterInput, appConst.mediumTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_controller_selector'); - throw new Error("Controller selector should not be visible, screenshot: " + screenshot + " " + err); + throw new Error(`Controller selector should not be visible, screenshot:${screenshot} ` + err); } } @@ -687,8 +691,8 @@ class ContentWizardPanel extends Page { } return await this.pause(500); } catch (err) { - await this.saveScreenshot(appConst.generateRandomName('err_site')); - throw new Error("Content Wizard, error during the typing data" + err); + let screenshot = await this.saveScreenshotUniqueName('err_site'); + throw new Error(`Content Wizard, error during creating the content, screenshot:${screenshot} ` + err); } } @@ -698,8 +702,8 @@ class ContentWizardPanel extends Page { await this.clickOnElement(this.publishDropDownHandle); return await this.pause(400); } catch (err) { - await this.saveScreenshot(appConst.generateRandomName('err_click_on_dropdown')); - throw new Error("Error when clicking on Publish dropdown handle " + err); + let screenshot = await this.saveScreenshotUniqueName('err_click_on_dropdown'); + throw new Error(`Error occurred after clicking on Publish dropdown handle, ${screenshot} ` + err); } } @@ -709,7 +713,7 @@ class ContentWizardPanel extends Page { await this.waitForElementDisplayed(this.unpublishMenuItem, appConst.mediumTimeout); await this.clickOnElement(this.unpublishMenuItem); } catch (err) { - throw new Error("Error during clicking on unpublish menu item " + err); + throw new Error("Error occurred after clicking on unpublish menu item " + err); } } @@ -729,7 +733,7 @@ class ContentWizardPanel extends Page { await this.pause(500); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_minimize_icon'); - throw new Error('Content wizard minimize toggler, screenshot: ' + screenshot + ' ' + err); + throw new Error(`Content wizard minimize toggler, screenshot: ${screenshot} ` + err); } } @@ -753,7 +757,7 @@ class ContentWizardPanel extends Page { } async waitForMarkAsReadyButtonVisible() { - let selector = XPATH.container + XPATH.markAsReadyButton; + let selector = XPATH.container + XPATH.publishMenuButton + XPATH.markAsReadyButton; return await this.waitForElementDisplayed(selector, appConst.mediumTimeout); } @@ -839,7 +843,8 @@ class ContentWizardPanel extends Page { async clickOnMarkAsReadyButton() { try { - let selector = XPATH.container + XPATH.markAsReadyButton; + let selector = XPATH.container + XPATH.publishMenuButton + XPATH.markAsReadyButton; + let aa = await this.findElements(selector); await this.waitForMarkAsReadyButtonVisible(); await this.clickOnElement(selector); return await this.pause(1000); @@ -1016,7 +1021,7 @@ class ContentWizardPanel extends Page { return await this.waitForElementDisplayed(this.modifyPathSpan, appConst.mediumTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_modify_path_span'); - throw new Error("Modify path span should be displayed, screenshot:" + screenshot + ' ' + err); + throw new Error(`Modify path span should be displayed, screenshot: ${screenshot} ` + err); } } @@ -1035,7 +1040,7 @@ class ContentWizardPanel extends Page { return this.waitForElementDisplayed(this.resetButton, appConst.longTimeout); } catch (err) { let screenshot = await this.saveScreenshotUniqueName('err_reset_button'); - throw new Error("Reset button is not displayed in the content wizard, screenshot:" + screenshot + " " + err); + throw new Error(`Reset button is not displayed in the content wizard, screenshot: ${screenshot} ` + err); } } @@ -1127,11 +1132,42 @@ class ContentWizardPanel extends Page { await this.clickOnElement(this.showChangesToolbarButton); } + async waitForToolbarRoleAttribute(expectedRole) { + let locator = XPATH.container + XPATH.toolbar; + await this.waitForAttributeValue(locator, appConst.ACCESSIBILITY_ATTRIBUTES.ROLE, expectedRole); + } + + async waitForToolbarAriaLabelAttribute() { + let locator = XPATH.container + XPATH.toolbar; + await this.waitForAttributeIsPresent(locator, appConst.ACCESSIBILITY_ATTRIBUTES.ARIA_LABEL); + } + + async waitForProjectViewerAriaLabelAttribute() { + let locator = XPATH.container + XPATH.projectViewerDiv; + await this.waitForAttributeIsPresent(locator, appConst.ACCESSIBILITY_ATTRIBUTES.ARIA_LABEL); + } + + + async waitForPublishMenuDropdownRoleAttribute(expectedRole) { + let locator = XPATH.toolbarPublish + lib.BUTTONS.DROP_DOWN_HANDLE; + await this.waitForAttributeValue(locator, appConst.ACCESSIBILITY_ATTRIBUTES.ROLE, expectedRole); + } + + async openLayersWidget() { + let wizardLayersWidget = new WizardLayersWidget(); + let wizardDetailsPanel = new DetailsPanel(); + await this.openDetailsPanel(); + await wizardDetailsPanel.openLayers(); + await wizardLayersWidget.waitForWidgetLoaded(); + return wizardLayersWidget; + } async openPublishReportWidget() { let wizardDetailsPanel = new DetailsPanel(); await this.openDetailsPanel(); await wizardDetailsPanel.openPublishReport(); } + + } module.exports = ContentWizardPanel; diff --git a/testing/specs/archive.browse.panel.spec.js b/testing/specs/archive.browse.panel.spec.js index bf31377f..411591d2 100644 --- a/testing/specs/archive.browse.panel.spec.js +++ b/testing/specs/archive.browse.panel.spec.js @@ -67,6 +67,8 @@ describe('archive.browse.panel.spec: tests for archive browse panel and selectio assert.equal(displayNames.length, 1, 'Single item should be present in the filtered grid'); // 5. Verify that checkboxes are clickable: Unselect one item in the filtered grid: await archiveBrowsePanel.clickOnCheckboxByName(FOLDER1.displayName); + await archiveBrowsePanel.pause(2000); + await studioUtils.saveScreenshot('grid_returned_to_initial_state'); // 6. Verify that the selection toggler(circle in the toolbar) gets not visible : await archiveBrowsePanel.waitForSelectionTogglerNotVisible(); // 7. Verify that Grid returns to the initial state: diff --git a/testing/specs/layers.widget.localize.button.spec.js b/testing/specs/layers.widget.localize.button.spec.js index 4ab4b92c..618f59ef 100644 --- a/testing/specs/layers.widget.localize.button.spec.js +++ b/testing/specs/layers.widget.localize.button.spec.js @@ -99,7 +99,7 @@ describe('layers.widget.localize.button.spec - checks Localize button in browse let browseLayersWidget = await studioUtils.openLayersWidgetInBrowsePanel(); // 2. Click on 'Localize' button: await browseLayersWidget.clickOnLocalizeButton(LAYER_DISPLAY_NAME); - await studioUtils.doSwitchToNextTab(); + await studioUtils.switchToContentTabWindow(FOLDER_NAME); // 3. Verify that expected content is loaded in wizard page: await contentWizard.waitForOpened(); await contentWizard.waitForSaveButtonDisabled(); @@ -179,6 +179,7 @@ describe('layers.widget.localize.button.spec - checks Localize button in browse await contentWizardPanel.waitForOpened(); // 3. Open Layers widget in the wizard: let wizardLayersWidget = await contentWizardPanel.openLayersWidget(); + await studioUtils.saveScreenshot('layers_name_issue1'); let layers = await wizardLayersWidget.getLayersName(); // 4. Verify names of layers: assert.equal(layers[0], 'Default', 'Default layer should be present in the widget'); diff --git a/testing/wdio.chrome.conf.js b/testing/wdio.chrome.conf.js index 5c3cf431..d1e9948c 100644 --- a/testing/wdio.chrome.conf.js +++ b/testing/wdio.chrome.conf.js @@ -26,7 +26,7 @@ exports.config = { // Enables colors for log output. coloredLogs: true, - baseUrl: 'http://localhost:8080/admin/tool', + baseUrl: 'http://localhost:8080/admin', // // Default timeout for all waitForXXX commands. waitforTimeout: 3000,