diff --git a/.github/workflows/a11y.yaml b/.github/workflows/a11y.yaml index f81d137336..f7b058ec7f 100644 --- a/.github/workflows/a11y.yaml +++ b/.github/workflows/a11y.yaml @@ -18,7 +18,7 @@ on: PACKAGES_AUTH_USER: description: 'PACKAGES_AUTH_USER' required: true - PACKAGES_AUTH_TOKEN: + PACKAGES_AUTH_TOKEN: description: 'PACKAGES_AUTH_TOKEN' required: true @@ -31,42 +31,49 @@ jobs: a11y: runs-on: [self-hosted, master] steps: - - uses: actions/checkout@v2 - with: - ref: ${{ env.BRANCH_NAME }} + - uses: actions/checkout@v2 + with: + ref: ${{ env.BRANCH_NAME }} - - run: git config user.name "nuxeo-webui-jx-bot" && git config user.email "webui@hyland.com" + - run: git config user.name "nuxeo-webui-jx-bot" && git config user.email "webui@hyland.com" - - uses: actions/setup-node@v3 - with: - registry-url: ${{ env.NPM_REPOSITORY }} - node-version: 14 - scope: '@nuxeo' + - uses: actions/setup-node@v3 + with: + registry-url: ${{ env.NPM_REPOSITORY }} + node-version: 18 + scope: '@nuxeo' - - uses: actions/setup-java@v2 - with: - distribution: 'zulu' - java-version: '11' + - name: Install Web UI + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_PACKAGES_TOKEN }} + run: | + npm install + pushd packages/nuxeo-web-ui-ftest + npm install + popd + pushd packages/nuxeo-designer-catalog + npm install + popd - - name: Install google chrome - run: | - wget https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_114.0.5735.90-1_amd64.deb - apt install -y --allow-downgrades ./google-chrome-stable_114.0.5735.90-1_amd64.deb + - uses: actions/setup-java@v2 + with: + distribution: 'zulu' + java-version: '11' - - name: 'Update settings.xml with server configuration' - run: | - echo ' - - - maven-internal - ${{ secrets.PACKAGES_AUTH_USER }} - ${{ secrets.PACKAGES_AUTH_TOKEN }} - - - ' > ~/.m2/settings.xml + - name: 'Update settings.xml with server configuration' + run: | + echo ' + + + maven-internal + ${{ secrets.PACKAGES_AUTH_USER }} + ${{ secrets.PACKAGES_AUTH_TOKEN }} + + + ' > ~/.m2/settings.xml - - name: Web UI build - run: mvn -B -ntp install + - name: Web UI build + run: mvn -B -ntp install - - name: A11y checks - run: mvn -B -ntp -f plugin/a11y install + - name: A11y checks + run: mvn -B -ntp -f plugin/a11y install diff --git a/.github/workflows/ftest.yaml b/.github/workflows/ftest.yaml index 4e4a2d9fbc..9cbcba10b7 100644 --- a/.github/workflows/ftest.yaml +++ b/.github/workflows/ftest.yaml @@ -39,17 +39,13 @@ jobs: with: registry-url: ${{ env.NPM_REPOSITORY }} scope: '@nuxeo' + node-version: 18 - uses: actions/setup-java@v2 with: distribution: 'zulu' java-version: '11' - - name: Install google chrome - run: | - wget -q https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_114.0.5735.90-1_amd64.deb - apt install -y --allow-downgrades ./google-chrome-stable_114.0.5735.90-1_amd64.deb - - name: Determine nuxeo-elements branch to link id: pick_nuxeo_elements_branch run: | @@ -99,6 +95,19 @@ jobs: popd popd + - name: add .npmrc + run: | + pushd /tmp/_temp/ + ls + rm .npmrc + touch .npmrc + popd + echo ' + packages.nuxeo.com/repository/npm-public/:_auth=${NODE_AUTH_TOKEN} + @nuxeo:registry=https://packages.nuxeo.com/repository/npm-public/ + always-auth=true + ' >> /tmp/_temp/.npmrc + - name: Link elements to Web UI run: | npm install --no-package-lock --@nuxeo:registry="${{ env.NPM_REPOSITORY }}" nuxeo-elements/core/${ELEMENTS_CORE} diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 89dfa685fb..dd625b005d 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -30,7 +30,7 @@ jobs: - uses: actions/setup-node@v3 with: registry-url: 'https://packages.nuxeo.com/repository/npm-public/' - node-version: 14 + node-version: 18 scope: '@nuxeo' - name: Install diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml index 5c8ef97767..6cb902fb5c 100644 --- a/.github/workflows/preview.yaml +++ b/.github/workflows/preview.yaml @@ -41,7 +41,7 @@ jobs: steps: - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 18 registry-url: 'https://packages.nuxeo.com/repository/npm-public/' scope: '@nuxeo' diff --git a/.github/workflows/promote.yaml b/.github/workflows/promote.yaml index 9b05c5279d..9f8dbd3237 100644 --- a/.github/workflows/promote.yaml +++ b/.github/workflows/promote.yaml @@ -21,7 +21,7 @@ jobs: steps: - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 18 registry-url: 'https://packages.nuxeo.com/repository/npm-public/' scope: '@nuxeo' diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 5f3cfedd17..23af4ed8d2 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -34,7 +34,7 @@ jobs: with: registry-url: 'https://packages.nuxeo.com/repository/npm-public/' scope: '@nuxeo' - node-version: 14 + node-version: 18 - name: Install env: diff --git a/addons/nuxeo-csv/ftest/features/step_definitions/csv-import.js b/addons/nuxeo-csv/ftest/features/step_definitions/csv-import.js deleted file mode 100644 index 144b78303f..0000000000 --- a/addons/nuxeo-csv/ftest/features/step_definitions/csv-import.js +++ /dev/null @@ -1,28 +0,0 @@ -import { When } from '@cucumber/cucumber'; - -/** - * Import the csv file - * - * @deprecated since 3.0.3. Please use "I upload the (.+) on the tab content page" located in create_dialog.js - * */ -When(/^I import the (.+) file$/, function(file) { - const dialog = this.ui.createDialog; - dialog.waitForVisible(); - dialog.setFileToImport(file); - dialog.selectedFileToImport.waitForVisible().should.be.true; - dialog.importCSVButton.click(); - dialog.importSuccess.waitForVisible(); - dialog.importCloseButton.waitForVisible(); - dialog.importCloseButton.click(); -}); - -When('I can see that the csv file is imported with no errors', function() { - const dialog = this.ui.createDialog; - dialog.waitForVisible(); - dialog.selectedCSVToImport.waitForVisible().should.be.true; - dialog.importCSVButton.click(); - dialog.importSuccess.waitForVisible(); - dialog.importError.isVisible().should.be.false; - dialog.importCloseButton.waitForVisible(); - dialog.importCloseButton.click(); -}); diff --git a/addons/nuxeo-spreadsheet/ftest/.eslintrc b/addons/nuxeo-spreadsheet/ftest/.eslintrc deleted file mode 100644 index df77738a91..0000000000 --- a/addons/nuxeo-spreadsheet/ftest/.eslintrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "globals": { - "driver": true, - "assert": true, - "expect": true - } -} diff --git a/addons/nuxeo-spreadsheet/ftest/features/step_definitions/spreadsheet.js b/addons/nuxeo-spreadsheet/ftest/features/step_definitions/spreadsheet.js deleted file mode 100644 index eebbf815c7..0000000000 --- a/addons/nuxeo-spreadsheet/ftest/features/step_definitions/spreadsheet.js +++ /dev/null @@ -1,66 +0,0 @@ -import { Then, When } from '@cucumber/cucumber'; -import Spreadsheet from '../../pages/spreadsheet'; - -When('I open the spreadsheet', function() { - const button = this.ui.results.actions.element('nuxeo-spreadsheet-button').click(); - - button.waitForVisible('#dialog'); - - const iframe = button.element('#iframe'); - driver.frame(iframe.value); - - this.spreadsheet = new Spreadsheet(); -}); - -When('I see the spreadsheet dialog', function() { - const button = this.ui.browser.results.actions.element('nuxeo-spreadsheet-button'); - button.waitForVisible('#dialog'); -}); - -Then('I can see the spreadsheet results actions button', function() { - const { results } = this.ui; - - if (results.displayMode !== 'table') { - results.toggleTableView.click(); - } - - results.actions.waitForVisible('nuxeo-spreadsheet-button'); -}); - -Then('I can see the {string} spreadsheet column', function(column) { - assert(this.spreadsheet, 'Spreadsheet editor does not exist'); - return this.spreadsheet.headers.includes(column); -}); - -When('I set the spreadsheet cell {int},{int} to {string}', function(row, col, value) { - const { spreadsheet } = this; - assert(spreadsheet, 'Spreadsheet does not exist'); - - spreadsheet.setData(row, col, value); -}); - -When('I save the spreadsheet', function() { - const { spreadsheet } = this; - assert(spreadsheet, 'Spreadsheet does not exist'); - - spreadsheet.save(); - - const { console } = spreadsheet; - driver.waitUntil(() => console.getText() === '1 rows saved'); -}); - -When('I close the spreadsheet', function() { - const { spreadsheet } = this; - assert(spreadsheet, 'Spreadsheet does not exist'); - - spreadsheet.close(); - driver.frame(); -}); - -Then('I see {string} in the results table cell {int},{int}', function(value, row, col) { - const { results } = this.ui; - results.waitForVisible(); - const tableRow = results.el.elements('nuxeo-data-table-row:not([header])').value[row]; - const tableCell = tableRow.elements('nuxeo-data-table-cell').value[col]; - expect(tableCell.getText()).to.equal(value); -}); diff --git a/addons/nuxeo-spreadsheet/ftest/pages/spreadsheet.js b/addons/nuxeo-spreadsheet/ftest/pages/spreadsheet.js deleted file mode 100644 index b026ebf773..0000000000 --- a/addons/nuxeo-spreadsheet/ftest/pages/spreadsheet.js +++ /dev/null @@ -1,62 +0,0 @@ -export default class Spreadsheet { - constructor() { - driver.waitUntil(() => driver.execute(() => window.spreadheet)); - } - - element(...params) { - return driver.element(...params); - } - - get table() { - return this.element('table.htCore'); - } - - get headers() { - return this.table.elements('thead span').value.map((e) => e.getText()); - } - - get rows() { - return this.table.elements('tbody tr'); - } - - get console() { - return this.element('#console'); - } - - /** - * Set data at given row and cell - */ - setData(row, cell, data) { - this._callHandsontable('setDataAtCell', row, cell, data); - } - - /** - * Get data at given row and cell - */ - getData(row, cell) { - return this._callHandsontable('getDataAtCell', row, cell); - } - - /** - * Save the data - */ - save() { - // click() was resulting "no element reference returned by script" - driver.execute((el) => el.click(), this.element('#save').value); - } - - /** - * Close the spreadsheet - */ - close() { - driver.execute((el) => el.click(), this.element('#close').value); - } - - /** - * Call a Handsontable method - */ - _callHandsontable(method, ...params) { - // eslint-disable-next-line no-undef, no-shadow - driver.execute((method, ...params) => window.spreadsheet.ht[method](...params), method, ...params); - } -} diff --git a/ftest/features/create_doc.feature b/ftest/features/create_doc.feature index 4b83e2634e..ea7dd33823 100644 --- a/ftest/features/create_doc.feature +++ b/ftest/features/create_doc.feature @@ -9,7 +9,7 @@ Feature: Create Document And I have permission ReadWrite for this document And I browse to the document - Scenario Outline: Create + Scenario Outline: Create and verify metadata properties When I click the Create Document button And I select from the Document Type menu And I create a document with the following properties: @@ -33,6 +33,22 @@ Feature: Create Document | doctype | | Note | | File | + + Scenario Outline: Create + When I click the Create Document button + And I select from the Document Type menu + And I create a document with the following properties: + | name | value | + | title | my title | + | description | my description | + | nature | Application | + | subjects | Gastronomy,Comics | + | expired | February 28, 2018 | + + Then I see the page + + Examples: + | doctype | | Folder | | Workspace | | Collection | diff --git a/addons/nuxeo-csv/ftest/features/csv-import.feature b/ftest/features/csv-import.feature similarity index 100% rename from addons/nuxeo-csv/ftest/features/csv-import.feature rename to ftest/features/csv-import.feature diff --git a/ftest/features/search.feature b/ftest/features/search.feature index a2e8ec628c..80b07a23ea 100644 --- a/ftest/features/search.feature +++ b/ftest/features/search.feature @@ -46,17 +46,6 @@ Feature: Search | coverage | Europe/Portugal | 5 | #| size | Between 100 KB and 1 MB | 1 | disabled until scroll works in shadow dom - Scenario: Default Saved Search - When I click the "defaultSearch" button - And I perform a coverage search for Europe/France on defaultSearch - Then I edit the results columns to show "Subjects" - And I save my search as "Local Search" - And I share my "defaultSearch" search with JSmith - When I logout - And I login as "JSmith" - And I click the "defaultSearch" button - Then I can view my saved search "Local Search" on "defaultSearch" - Scenario: Navigate to Default Saved Search by ID Given I have a saved search named "Portugal", for the "default_search" page provider, with the following parameters | key | value | @@ -109,3 +98,14 @@ Feature: Search When I click the "assetsSearch" button And I perform a fulltext search for picture on assetsSearch Then I can see 3 search results + + Scenario: Default Saved Search + When I click the "defaultSearch" button + And I perform a coverage search for Europe/France on defaultSearch + Then I edit the results columns to show "Subjects" + And I save my search as "Local Search" + And I share my "defaultSearch" search with JSmith + When I logout + And I login as "JSmith" + And I click the "defaultSearch" button + Then I can view my saved search "Local Search" on "defaultSearch" diff --git a/addons/nuxeo-spreadsheet/ftest/features/spreadsheet.feature b/ftest/features/spreadsheet.feature similarity index 100% rename from addons/nuxeo-spreadsheet/ftest/features/spreadsheet.feature rename to ftest/features/spreadsheet.feature diff --git a/addons/nuxeo-csv/ftest/resources/csv-import-sample.csv b/ftest/resources/csv-import-sample.csv similarity index 100% rename from addons/nuxeo-csv/ftest/resources/csv-import-sample.csv rename to ftest/resources/csv-import-sample.csv diff --git a/index.js b/index.js index 307831b5ee..6776d221d9 100644 --- a/index.js +++ b/index.js @@ -28,13 +28,17 @@ const loadAddons = async () => { }), ); }; -const setupApp = () => +const setupApp = async () => customElements.whenDefined('nuxeo-app').then(() => { - Nuxeo.UI.app = document.querySelector('nuxeo-app'); - if (!Nuxeo.UI.app) { + if (Nuxeo && Nuxeo.UI) { + Nuxeo.UI.app = document.querySelector('nuxeo-app'); + if (!Nuxeo.UI.app) { + console.error('could not find nuxeo-app'); + } + setFallbackNotificationTarget(Nuxeo.UI.app); + } else { console.error('could not find nuxeo-app'); } - setFallbackNotificationTarget(Nuxeo.UI.app); }); const loadRouting = async () => { if (config.get('router.htmlImport')) { diff --git a/karma.conf.js b/karma.conf.js index bd631dee73..2c97d66fc9 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -50,6 +50,7 @@ module.exports = (config) => { config.set({ sauceLabs, + hostname: '127.0.0.1', basePath: '', singleRun: true, browsers: config.browsers && config.browsers.length > 0 ? config.browsers : Object.keys(customLaunchers), diff --git a/package.json b/package.json index 7895ed5d38..9216e9819b 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,13 @@ "license": "Apache-2.0", "vendor": "Nuxeo", "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" + }, + "config": { + "workboxCli": "3.6.3" }, "devDependencies": { - "@cucumber/cucumber": "^7.0.0", + "@cucumber/cucumber": "^9.5.1", "@nuxeo/nuxeo-web-ui-ftest": "file:./packages/nuxeo-web-ui-ftest", "@nuxeo/testing-helpers": "~3.0.30-rc.0", "@open-wc/eslint-config": "^0.3.0", @@ -55,9 +58,9 @@ "style-loader": "^2.0.0", "url-loader": "^4.1.1", "vm-browserify": "^1.1.2", - "wdio-chromedriver-service": "^8.0.0", + "wdio-chromedriver-service": "^8.1.1", "wdio-cucumber-reporter": "0.0.2", - "wdio-json-reporter": "^2.0.0", + "wdio-json-reporter": "^3.0.0", "webpack": "^5.3.0", "webpack-bundle-analyzer": "^3.9.0", "webpack-cli": "^4.1.0", @@ -74,7 +77,7 @@ "prebuild": "npm-run-all prepare:*", "prepare:tmp": "rm -rf .tmp", "prepare:i18n": "node scripts/merge-messages.js", - "prepare:workbox": "workbox copyLibraries .tmp && mv .tmp/workbox-v$npm_package_devDependencies_workbox_cli .tmp/workbox", + "prepare:workbox": "workbox copyLibraries .tmp && mv .tmp/workbox-v${npm_package_config_workboxCli} .tmp/workbox", "build": "webpack --env production", "postbuild": "npm-run-all fix:*", "fix:preview": "replace 'elements/' '${window.location.pathname}/' dist/index.html", @@ -174,7 +177,7 @@ "@polymer/paper-toolbar": "^3.0.1", "@polymer/paper-tooltip": "^3.0.1", "@polymer/polymer": "^3.5.1", - "@wdio/allure-reporter": "^7.2.0", + "@wdio/allure-reporter": "^7.32.0", "@webcomponents/html-imports": "^1.2.0", "aws-sdk": "^2.420.0", "dotenv": "^8.0.0", @@ -190,7 +193,7 @@ "three": "~0.125.0", "uuid": "^3.3.2", "web-animations-js": "^2.3.1", - "webdriverio": "^7.16.16" + "webdriverio": "^8.20.4" }, "husky": { "hooks": { diff --git a/packages/nuxeo-web-ui-ftest/.eslintrc b/packages/nuxeo-web-ui-ftest/.eslintrc index df3fc81d35..c6f9a64870 100644 --- a/packages/nuxeo-web-ui-ftest/.eslintrc +++ b/packages/nuxeo-web-ui-ftest/.eslintrc @@ -11,7 +11,9 @@ "users": true, "groups": true, "browser": true, - "moment": true + "moment": true, + "assert": true, + "expect": true }, "overrides": [ { diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/admin.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/admin.js index 181d25dcd6..7e9e248013 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/admin.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/admin.js @@ -1,50 +1,76 @@ -import { Given, Then, When } from '@cucumber/cucumber'; +import { Given, Then, When } from '../../node_modules/@cucumber/cucumber'; -Then('I can see the administration menu', function() { - this.ui.drawer.administration.waitForVisible().should.be.true; +Then('I can see the administration menu', async function() { + const { drawer } = this.ui; + const element = await drawer.administration; + const isVisible = element.waitForVisible(); + if (!isVisible) { + throw new Error('Expected administration menu to be visible'); + } }); -Then('I cannot see the administration button', function() { - this.ui.adminButton.waitForVisible(browser.options.waitForTimeout, true).should.be.true; +Then('I cannot see the administration button', async function() { + const isVisible = await this.ui.adminButton.isVisible(); + if (isVisible) { + throw new Error('Expected administration button to not be visible'); + } }); // XXX: this.ui.drawer.administration.click() -When('I click {string} in the administration menu', (text) => { - const el = driver.element(`nuxeo-menu-item[name="${text}"]`); - el.waitForVisible(); - el.click(); +When('I click {string} in the administration menu', async (text) => { + const el = await driver.$(`nuxeo-menu-item[name="${text}"]`); + setTimeout(async () => { + await el.waitForVisible(); + el.click(); + }, 2000); }); -Then('I can see the analytics page', function() { - this.ui.administration.analytics.waitForVisible(); +Then('I can see the analytics page', async function() { + await this.ui.administration.analytics; }); -Then('I can see the users and groups page', function() { - this.ui.administration.userAndGroupManagement.waitForVisible().should.be.true; +Then('I can see the users and groups page', async function() { + await this.ui.administration.userAndGroupManagement; }); -Then('I can see the vocabulary page', function() { - this.ui.administration.vocabularyManagement.waitForVisible().should.be.true; +Then('I can see the vocabulary page', async function() { + const adminstration = await this.ui.administration; + const vocabManagement = await adminstration.vocabularyManagement; + const isVisible = await vocabManagement.waitForVisible(); + if (!isVisible) { + throw new Error('Expected vocabulary page to be visible'); + } }); -Then('I can see the audit page', function() { - this.ui.administration.audit.waitForVisible().should.be.true; +Then('I can see the audit page', async function() { + const ui = await this.ui; + const admin = await ui.administration; + const auditPage = await admin.audit; + const isVisible = auditPage.isVisible(); + if (!isVisible) { + throw new Error('Expected audit page to be visible'); + } }); -Then('I can see the nxql search page', function() { - this.ui.administration.nxqlSearch.waitForVisible().should.be.true; +Then('I can see the nxql search page', async function() { + await this.ui.administration.nxqlSearch; }); -Then('I can see the cloud services page', function() { - this.ui.administration.cloudServices.waitForVisible().should.be.true; +Then('I can see the cloud services page', async function() { + const isVisible = await this.ui.administration.cloudServices.waitForVisible(); + if (!isVisible) { + throw new Error('Expected cloud services page to be visible'); + } }); -Given('I am on cloud services page', function() { - this.ui.administration.goToCloudServices(); +Given('I am on cloud services page', async function() { + await this.ui.administration.goToCloudServices(); }); // ¯\_(ツ)_/¯ no way to escape a / character in cucumber expressions -When(/^I click the new user\/group button$/, function() { - this.ui.administration.userGroupCreateButton.waitForVisible(); - this.ui.administration.userGroupCreateButton.click(); +When(/^I click the new user\/group button$/, async function() { + const adminEle = await this.ui.administration; + const userGroupEle = await adminEle.userGroupCreateButton; + await userGroupEle.waitForVisible(); + await userGroupEle.click(); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/audit.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/audit.js index e3301a8213..b9c388571e 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/audit.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/audit.js @@ -1,13 +1,18 @@ -import { Then } from '@cucumber/cucumber'; +import { Then } from '../../node_modules/@cucumber/cucumber'; -Then('I can see the audit table', function() { - this.ui.administration.audit.isAuditTableDisplayed.should.be.true; +Then('I can see the audit table', async function() { + const isAuditTableDisplay = await this.ui.administration.audit.isAuditTableDisplayed; + isAuditTableDisplay.should.be.true; }); -Then('I have a non empty audit table', function() { - this.ui.administration.audit.isAuditTableFilled.should.be.true; +Then('I have a non empty audit table', async function() { + const isAuditTableFilled = await this.ui.administration.audit.isAuditTableFilled; + isAuditTableFilled.should.be.true; }); -Then('I can see {string} entry in audit table', function(performedAction) { - this.ui.administration.audit.waitForHasEntry(performedAction).should.be.true; +Then('I can see {string} entry in audit table', async function(performedAction) { + const administration = await this.ui.administration; + const audit = await administration.audit; + const hasEntry = await audit.waitForHasEntry(performedAction); + hasEntry.should.be.true; }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/browser.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/browser.js index 1bb8dae76c..e6bd6d4506 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/browser.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/browser.js @@ -1,224 +1,282 @@ -import { Then, When } from '@cucumber/cucumber'; +/* eslint-disable no-await-in-loop */ +import { Then, When } from '../../node_modules/@cucumber/cucumber'; -Then('I can see the {word} tree', function(tab) { - this.ui.drawer._section(tab).waitForVisible().should.be.true; +Then('I can see the {word} tree', async function(tab) { + const drawer = await this.ui.drawer; + await drawer._section(tab); + const isVisible = await drawer.waitForVisible(); + isVisible.should.be.true; }); -Then('I can see the {string} {word} tree node', function(title, tab) { - this.ui.drawer._section(tab).waitForVisible(); - driver.waitUntil(() => - this.ui.drawer - ._section(tab) - .elements('.content a') - .some((e) => e.getText() === title), +Then('I can see the {string} {word} tree node', async function(title, tab) { + const drawer = await this.ui.drawer; + const sectionTab = await drawer._section(tab); + await sectionTab.waitForVisible(); + driver.pause(10000); + await sectionTab.$$('.content a'); + + await driver.waitUntil( + async () => { + const sectionText = await sectionTab.$$('.content a').map((elem) => elem.getText()); + const someSectionText = sectionText.some((e) => e === title); + return someSectionText; + }, + { + timeout: 10000, + timeoutMsg: 'expecteed 1 text to be differeent after 5s', + }, ); }); -Then('I can navigate to {word} pill', function(pill) { - this.ui.browser.waitForVisible(); - const el = this.ui.browser.el.element(`nuxeo-page-item[name='${pill.toLowerCase()}']`); - el.waitForVisible(); - el.click(); - this.ui.browser.waitForVisible(`#nxContent [name='${pill.toLowerCase()}']`); +Then('I can navigate to {word} pill', async function(pill) { + await driver.pause(3000); + const browser = await this.ui.browser; + await browser.waitForVisible(); + const ele = await browser.el.$(`nuxeo-page-item[name='${pill.toLowerCase()}']`); + await ele.waitForVisible(); + await ele.click(); + await browser.waitForVisible(`#nxContent [name='${pill.toLowerCase()}']`); + await driver.pause(3000); }); -Then('I cannot see to {word} pill', function(pill) { - this.ui.browser.waitForVisible(); - this.ui.browser.waitForNotVisible(`nuxeo-page-item[name='${pill.toLowerCase()}']`).should.be.true; +Then('I cannot see to {word} pill', async function(pill) { + const browser = await this.ui.browser; + await browser.waitForVisible(); + const outElement = await browser.waitForNotVisible(`nuxeo-page-item[name='${pill.toLowerCase()}']`); + outElement.should.be.true; }); -Then('I am on the {word} pill', function(pill) { - this.ui.browser.waitForVisible(); - this.ui.browser.currentPageName.should.equal(pill); +Then('I am on the {word} pill', async function(pill) { + await this.ui.browser.waitForVisible(); + const currentPageEle = await this.ui.browser.currentPageName; + currentPageEle.should.equal(pill); }); -When('I click {string} in the {word} tree', function(title, tab) { - const section = this.ui.drawer._section(tab); - section.waitForVisible(); - driver.waitUntil(() => section.elements('.content a').some((e) => e.getText() === title)); - const el = section.elements('.content a').find((e) => e.getText() === title); - el.waitForVisible(); - el.click(); +When('I click {string} in the {word} tree', async function(title, tab) { + const drawer = await this.ui.drawer; + const sectionTab = await drawer._section(tab); + await sectionTab.waitForVisible(); + await driver.pause(3000); + const sectionText = await sectionTab.$$('.content a').map((element) => element.getText()); + const el = await sectionTab.elements('.content a'); + let index; + for (let i = 0; i < sectionText.length; i++) { + const item = sectionText[i]; + if (item === title) { + index = i; + break; + } + } + if (index > -1) { + const elEle = await el[index]; + await elEle.waitForVisible(); + await elEle.click(); + } else { + throw Error(`Expected title to be ${title} but not found`); + } }); -Then('I can see the {string} document', function(title) { - this.ui.browser.waitForVisible(); - this.ui.browser.hasTitle(title).should.be.true; +Then('I can see the {string} document', async function(title) { + const browser = await this.ui.browser; + await browser.waitForVisible(); + const browserTitle = await browser.hasTitle(title); + browserTitle.should.be.true; }); -Then('I select all child documents', function() { - this.ui.browser.waitForVisible(); - this.ui.browser.selectAllChildDocuments(); +Then('I select all child documents', async function() { + const browser = await this.ui.browser; + await browser.waitForVisible(); + await browser.selectAllChildDocuments(); }); -Then('I select all the documents', function() { - this.ui.browser.waitForVisible(); - this.ui.browser.selectAllDocuments(); +Then('I select all the documents', async function() { + const browser = await this.ui.browser; + await browser.waitForVisible(); + await browser.selectAllDocuments(); }); -Then('I deselect the {string} document', function(title) { - this.ui.browser.waitForVisible(); - this.ui.browser.deselectChildDocument(title); +Then('I deselect the {string} document', async function(title) { + const browser = await this.ui.browser; + await browser.waitForVisible(); + await browser.deselectChildDocument(title); }); -Then('I select the {string} document', function(title) { - this.ui.browser.waitForVisible(); - this.ui.browser.selectChildDocument(title); +Then('I select the {string} document', async function(title) { + const browser = await this.ui.browser; + await browser.waitForVisible(); + await browser.selectChildDocument(title); }); -Then('I can see the selection toolbar', function() { - this.ui.browser.waitForVisible(); - this.ui.browser.selectionToolbar.waitForVisible(); +Then('I can see the selection toolbar', async function() { + const browser = await this.ui.browser; + await browser.waitForVisible(); + const toolbar = await browser.selectionToolbar; + await toolbar.waitForVisible(); }); -When('I cannot see the display selection link', function() { - this.ui.browser.selectionToolbar.waitForNotVisible('.selectionLink').should.be.true; +When('I cannot see the display selection link', async function() { + const browser = await this.ui.browser; + await browser.waitForVisible(); + const selectionToolbarElem = await browser.selectionToolbar; + await driver.pause(3000); + await selectionToolbarElem.waitForVisible(); + const selectionLinkVisible = await selectionToolbarElem.waitForNotVisible('.selectionLink'); + selectionLinkVisible.should.be.true; }); -Then('I can add selection to the {string} collection', function(collectionName) { - this.ui.browser.waitForVisible(); - this.ui.browser.selectionToolbar.addToCollectionDialog.addToCollection(collectionName); +Then('I can add selection to the {string} collection', async function(collectionName) { + const browserEle = await this.ui.browser; + await browserEle.waitForVisible(); + const selectionToolEle = await browserEle.selectionToolbar; + const addToDialog = await selectionToolEle.addToCollectionDialog; + await addToDialog.addToCollection(collectionName); }); -Then('I can add selection to clipboard', function() { - this.ui.browser.waitForVisible(); - this.ui.browser.selectionToolbar.addToClipboard(); +Then('I can add selection to clipboard', async function() { + const browser = await this.ui.browser; + await browser.waitForVisible(); + const toolbar = await browser.selectionToolbar; + await toolbar.addToClipboard(); }); -Then('I can move selection down', function() { - this.ui.browser.waitForVisible(); - this.ui.browser.selectionToolbar.moveDown(); +Then('I can move selection down', async function() { + const browser = await this.ui.browser; + await browser.waitForVisible(); + const selectionToolbar = await browser.selectionToolbar; + await selectionToolbar.moveDown(); }); -Then('I can move selection up', function() { - this.ui.browser.waitForVisible(); - this.ui.browser.selectionToolbar.moveUp(); +Then('I can move selection up', async function() { + const browser = await this.ui.browser; + await browser.waitForVisible(); + const selectionToolbar = await browser.selectionToolbar; + await selectionToolbar.moveUp(); }); -Then('I can see the {string} child document is at position {int}', function(title, pos) { - this.ui.browser.waitForVisible(); - driver.waitUntil(() => this.ui.browser.indexOfChild(title) === pos - 1); +Then('I can see the {string} child document is at position {int}', async function(title, pos) { + await driver.pause(1000); + const browser = await this.ui.browser; + await browser.waitForVisible(); + const childIndex = await browser.indexOfChild(title); + if (childIndex !== pos - 1) { + throw Error(`${childIndex} child document not present at expected position`); + } }); -When('I sort the content by {string} in {string} order', function(field, order) { - this.ui.browser.waitForVisible(); - this.ui.browser.sortContent(field, order); +When('I sort the content by {string} in {string} order', async function(field, order) { + const browser = await this.ui.browser; + await browser.waitForVisible(); + await browser.sortContent(field, order); }); -Then('I can see {int} document(s)', function(numberOfResults) { - const { results } = this.ui.browser; - results.waitForVisible(); - - const { displayMode } = results; - driver.waitUntil(() => results.resultsCount(displayMode) === numberOfResults); +Then('I can see {int} document(s)', async function(numberOfResults) { + const browser = await this.ui.browser; + const uiResult = await browser.results; + const displayMode = await uiResult.displayMode; + const outResult = await uiResult.resultsCount(displayMode); + if (outResult !== numberOfResults) { + throw Error(`Expecting to get ${numberOfResults} results but found ${outResult}`); + } }); -Then(/^I can see the permissions page$/, function() { - this.ui.browser.permissionsView.waitForVisible(); +Then(/^I can see the permissions page$/, async function() { + await this.ui.browser.permissionsView.waitForVisible(); }); -Then(/^I can see the document has (\d+) publications$/, function(nbPublications) { - driver.waitUntil(() => this.ui.browser.publicationView.count === nbPublications); +Then(/^I can see the document has (\d+) publications$/, async function(nbPublications) { + const browser = await this.ui.browser; + const count = await browser.publicationView.count; + if ((await count) !== nbPublications) { + throw new Error(`Expected count to be equal ${nbPublications}`); + } }); -Then(/^I can see the document has the following publication$/, function(table) { - table.rows().forEach((row) => { - this.ui.browser.publicationView.hasPublication(row[0], row[1], row[2]).should.be.true; - }); +Then(/^I can see the document has the following publication$/, async function(table) { + const rows = table.rows(); + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + const publication = await this.ui.browser.publicationView; + const isRowPresent = await publication.hasPublication(row[0], row[1], row[2]); + await isRowPresent.should.be.true; + } }); -Then(/^I can republish the following publication$/, function(table) { - table.hashes().forEach((row) => { - const { path, rendition, version } = row; - // XXX we need to store the current version of the publication to check against the updated version after republish - let previousVersion; - driver.waitUntil(() => { - const pubRow = this.ui.browser.publicationView.getPublicationRow(path, rendition); - if (!pubRow) { - return false; - } - previousVersion = parseFloat( - pubRow - .getText('nuxeo-data-table-cell .version') - .trim() - .toLowerCase(), - ); - return !Number.isNaN(previousVersion); - }); - this.ui.browser.publicationView.republish(path, rendition, version); - // XXX we need to wait for the new version to be greater than the previous one, otherwise we can have the steps - // executed after this one operating over an outdated list of publications - driver.waitUntil(() => { - try { - const pubRow = this.ui.browser.publicationView.getPublicationRow(path, rendition); - if (!pubRow) { - return false; - } - const newVersion = parseFloat( - pubRow - .getText('nuxeo-data-table-cell .version') - .trim() - .toLowerCase(), - ); - if (Number.isNaN(newVersion)) { - return false; - } - return newVersion > previousVersion; - } catch (e) { - return false; - } - }); - }); +Then(/^I can republish the following publication$/, async function(table) { + const rows = table.hashes(); + for (let i = 0; i < rows.length; i++) { + const { path, rendition, version } = rows[i]; + let pubRow = await this.ui.browser.publicationView.getPublicationRow(path, rendition); + if (!pubRow) { + return false; + } + const ele = await pubRow.$('nuxeo-data-table-cell .version').getText(); + const previousVersion = parseFloat(ele.trim().toLowerCase()); + const browser = await this.ui.browser; + const publicationView = await browser.publicationView; + await publicationView.republish(path, rendition, version); + pubRow = await publicationView.getPublicationRow(path, rendition); + const eleNew = await pubRow.$('nuxeo-data-table-cell .version').getText(); + const newVersion = parseFloat(eleNew.trim().toLowerCase()); + if (Number.isNaN(newVersion)) { + throw Error('Failed to republish the document'); + } + return newVersion > previousVersion; + } }); -Then('I can publish selection to {string}', function(target) { - this.ui.browser.waitForVisible(); - this.ui.browser.selectionToolbar.publishDialog.publish(target); +Then('I can publish selection to {string}', async function(target) { + const browser = await this.ui.browser; + await browser.waitForVisible(); + const selectionToolBar = await browser.selectionToolbar; + const dialog = await selectionToolBar.publishDialog; + await dialog.publish(target); // HACK because publishing all documents is asynchronous - driver.pause(1000); + await driver.pause(2000); }); -Then(/^I can perform the following publications$/, function(table) { - let page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - let pubCount = page.publicationsCount; +Then(/^I can perform the following publications$/, async function(table) { + let page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + let pubCount = await page.publicationsCount; pubCount.should.not.be.NaN; - table.hashes().forEach((row) => { - const { target, rendition, version, override } = row; - this.ui.browser.publishDialog.publish(target, rendition, version, override); - // XXX We need to wait for the document to be updated after publishing, but this might take a while. If we don't - // do it, the next step can ve triggered before the view is updated, which can lead to an unexpected state. A way - // to achieve this is to wait for the number of publications to be updated on the document info panel. - driver.waitUntil(() => { - try { - page = this.ui.browser.documentPage(this.doc.type); - const newCount = page.publicationsCount; - let check; - // XXX if we pick a version that's not the latest, we no longer see the number of publications, and the versions - // bar will be displayed instead - if (page.isVisible('#versionInfoBar')) { - check = newCount === 0; - } else { - // XXX the problem might not be solved if we're only overriding one publication - check = override ? newCount === 1 : newCount > pubCount; - } - if (check) { - pubCount = page.publicationsCount; - return true; - } - } catch (e) { - return false; - } - }); - }); -}); - -Then('I can delete all the documents from the {string} collection', function(name) { - this.ui.browser.removeSelectionFromCollection(name); + const rows = table.hashes(); + for (let i = 0; i < rows.length; i++) { + const { target, rendition, version, override } = rows[i]; + const dialog = await this.ui.browser.publishDialog; + const isdocumentPublished = await dialog.publish(target, rendition, version, override); + isdocumentPublished.should.be.true; + page = await this.ui.browser.documentPage(this.doc.type); + const newCount = await page.publicationsCount; + let check; + const bar = await page.isVisible('#versionInfoBar'); + if (bar) { + check = newCount === 0; + } else { + check = override ? newCount === 1 : newCount > pubCount; + } + if (check) { + pubCount = page.publicationsCount; + } + } +}); + +Then('I can delete all the documents from the {string} collection', async function(name) { + const browser = await this.ui.browser; + await browser.removeSelectionFromCollection(name); // HACK - because the delete all is async - driver.pause(1000); + await driver.pause(1000); }); -Then('I can see the browser title as {string}', (title) => { - driver.waitUntil(() => title === browser.getTitle()); +Then('I can see the browser title as {string}', async (title) => { + driver.pause(3000); + await driver.waitUntil( + async () => { + const browserTitle = await browser.getTitle(); + return title === browserTitle; + }, + { + timeout: 10000, + timeoutMsg: 'expected 10 text to be different after 5s', + }, + ); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/bulk_edit.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/bulk_edit.js index fb57f8fb8c..1659f6fa4b 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/bulk_edit.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/bulk_edit.js @@ -1,23 +1,30 @@ -import { Then } from '@cucumber/cucumber'; +import { Then } from '../../node_modules/@cucumber/cucumber'; -Then('I click the bulk edit button with {string} layout', function(layoutName) { - this.ui.browser.selectionToolbar.clickResultsActionMenu(`nuxeo-edit-documents-button[layout=${layoutName}]`); +Then('I click the bulk edit button with {string} layout', async function(layoutName) { + const browser = await this.ui.browser; + await browser.waitForVisible(); + const selectionToolbarElem = await browser.selectionToolbar; + await selectionToolbarElem.waitForVisible(); + await selectionToolbarElem.clickResultsActionMenu(`nuxeo-edit-documents-button[layout=${layoutName}]`); }); -Then('I can bulk edit multiple properties in {string} layout:', function(layoutName, table) { - const action = this.ui.bulkEdit(`nuxeo-edit-documents-button[layout="${layoutName}"]`); - action.dialog.waitForDisplayed(); - action.editMultipleOptions(table); - action.saveButton.click(); +Then('I can bulk edit multiple properties in {string} layout:', async function(layoutName, table) { + const action = await this.ui.bulkEdit(`nuxeo-edit-documents-button[layout="${layoutName}"]`); + const dialog = await action.dialog; + await dialog.waitForDisplayed(); + await action.editMultipleOptions(table); + const saveButtonEle = await action.saveButton; + await saveButtonEle.click(); }); -Then('I see a toast notification with the following message {string}', function(message) { - const notificationMessage = this.ui.getToastMessage(message); +Then('I see a toast notification with the following message {string}', async function(message) { + const notificationMessage = await this.ui.getToastMessage(message); const trimmedMessage = message.trim().replace(/"/g, ''); notificationMessage.should.be.equals(trimmedMessage); }); -Then('I click the toast notification dismiss button', function() { - this.ui.getToastDismissButton().click(); - this.ui.waitForToastNotVisible(); +Then('I click the toast notification dismiss button', async function() { + const toastDismissButton = await this.ui.getToastDismissButton(); + await toastDismissButton.click(); + await this.ui.waitForToastNotVisible(); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/clipboard.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/clipboard.js index 00c9ddd455..4eed868c5d 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/clipboard.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/clipboard.js @@ -1,43 +1,71 @@ -import { Then, When } from '@cucumber/cucumber'; +/* eslint-disable no-await-in-loop */ +import { Then, When } from '../../node_modules/@cucumber/cucumber'; -When('I click remove button for {string} document', function(title) { - this.ui.drawer.clipboard.waitForVisible(); - this.ui.drawer.clipboard.removeItem(title); +When('I click remove button for {string} document', async function(title) { + const drawer = await this.ui.drawer; + const clipboard = await drawer.clipboard; + await clipboard.waitForVisible(); + await clipboard.removeItem(title); }); -When('I click the clipboard move action', function() { - if (!this.ui.drawer.clipboard.isVisible()) { - this.ui.drawer.open('clipboard'); +When('I click the clipboard move action', async function() { + const drawer = await this.ui.drawer; + const clipboard = await drawer.clipboard; + const isClipboarVisible = await clipboard.isVisible(); + if (!isClipboarVisible) { + await drawer.open('clipboard'); } - this.ui.waitForToastNotVisible(); - this.ui.drawer.clipboard.move(); + await this.ui.waitForToastNotVisible(); + await clipboard.move(); }); -When('I click the clipboard paste action', function() { - if (!this.ui.drawer.clipboard.isVisible()) { - this.ui.drawer.open('clipboard'); +When('I click the clipboard paste action', async function() { + const drawer = await this.ui.drawer; + const clipboard = await drawer.clipboard; + const isClipboarVisible = await clipboard.isVisible(); + if (!isClipboarVisible) { + await drawer.open('clipboard'); } - this.ui.waitForToastNotVisible(); - this.ui.drawer.clipboard.paste(); + await this.ui.waitForToastNotVisible(); + await clipboard.paste(); }); -Then('I can see the clipboard has {string} document', function(title) { - this.ui.drawer.clipboard.waitForVisible(); - driver.waitUntil(() => this.ui.drawer.clipboard.el.hasElementByTextContent('#list .list-item-title', title)); +Then('I can see the clipboard has {string} document', async function(title) { + const clipboardEle = await this.ui.drawer.clipboard; + await clipboardEle.waitForVisible(); + let found = false; + const clipboardItems = await clipboardEle.el.$$('#list .list-item-title'); + for (let index = 0; index < clipboardItems.length; index++) { + const elementText = await clipboardItems[index].getText(); + if (elementText === title) found = true; + } + return found; }); -Then('I can see the clipboard has {int} item(s)', function(nb) { - this.ui.drawer.clipboard.waitForVisible(); - driver.waitUntil(() => this.ui.drawer.clipboard.nbItems === nb); + +Then('I can see the clipboard has {int} item(s)', async function(nb) { + const drawer = await this.ui.drawer; + const clipboard = await drawer.clipboard; + await clipboard.waitForVisible(); + const nbItems = await clipboard.nbItems; + if (nbItems !== nb) { + throw Error(`Expected clipboard count to be ${nb} but found ${nbItems}`); + } }); -Then('I can see clipboard actions disabled', function() { - if (!this.ui.drawer.clipboard.isVisible()) { - this.ui.drawer.open('clipboard'); +Then('I can see clipboard actions disabled', async function() { + const drawer = await this.ui.drawer; + const clipboard = await drawer.clipboard; + const isClipboardVisible = await clipboard.isVisible(); + if (!isClipboardVisible) { + await drawer.open('clipboard'); } - const { moveButton } = this.ui.drawer.clipboard; - moveButton.waitForVisible(); - driver.waitUntil(() => moveButton.getAttribute('disabled') !== null); - - const { pasteButton } = this.ui.drawer.clipboard; - pasteButton.waitForVisible(); - driver.waitUntil(() => pasteButton.getAttribute('disabled') !== null); + const moveButton = await clipboard.moveButton; + await moveButton.waitForVisible(); + await driver.waitUntil(async () => (await moveButton.getAttribute('disabled')) !== null, { + timeoutMsg: 'step definition clipborad 65', + }); + const pasteButton = await clipboard.pasteButton; + await pasteButton.waitForVisible(); + await driver.waitUntil(async () => (await pasteButton.getAttribute('disabled')) !== null, { + timeoutMsg: 'step definition clipborad 70', + }); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/cloud.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/cloud.js index 65a913614d..0215c526d8 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/cloud.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/cloud.js @@ -1,4 +1,4 @@ -import { Given, Then, When } from '@cucumber/cucumber'; +import { Given, Then, When } from '../../node_modules/@cucumber/cucumber'; Given('provider {string} exists in providers', (provider) => fixtures.providers.create({ @@ -7,65 +7,93 @@ Given('provider {string} exists in providers', (provider) => }), ); -Then('I can see the nuxeo-cloud-providers page', function() { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.nuxeoCloudProviders.waitForVisible().should.be.true; -}); - -Then('I can see the nuxeo-cloud-tokens page', function() { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.nuxeoCloudTokens.waitForVisible().should.be.true; -}); - -Then('I can see the nuxeo-oauth2-provided-tokens table', function() { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.nuxeoCloudTokensAuthorizedApplications.waitForVisible().should.be.true; -}); - -Then('I can see the nuxeo-oauth2-consumed-tokens table', function() { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.nuxeoCloudTokensCloudAccount.waitForVisible().should.be.true; -}); - -Then('I can add the following provider:', function(provider) { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.addProvider(provider); +Then('I can see the nuxeo-cloud-providers page', async function() { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + const nuxeoCloudProvidersPage = await cloudServicesEle.nuxeoCloudProviders.waitForVisible(); + if (!nuxeoCloudProvidersPage) { + throw new Error('Expected nuxeo-cloud-providers page not be visible'); + } +}); + +Then('I can see the nuxeo-cloud-tokens page', async function() { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + const nuxeoCloudTokenPage = await cloudServicesEle.nuxeoCloudTokens.waitForVisible(); + if (!nuxeoCloudTokenPage) { + throw new Error('Expected nuxeo-cloud-tokens page not be visible'); + } +}); + +Then('I can see the nuxeo-oauth2-provided-tokens table', async function() { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + const nuxeoOauth2ProvidedEle = await cloudServicesEle.nuxeoCloudTokensAuthorizedApplications.waitForVisible(); + if (!nuxeoOauth2ProvidedEle) { + throw new Error('Expected nuxeo-oauth2-provided-tokens table not be visible'); + } +}); + +Then('I can see the nuxeo-oauth2-consumed-tokens table', async function() { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + const nuxeoOauth2ConsumedTokens = await cloudServicesEle.nuxeoCloudTokensCloudAccount.waitForVisible(); + if (!nuxeoOauth2ConsumedTokens) { + throw new Error('Expected nuxeo-oauth2-consumed-tokens table not be visible'); + } +}); + +Then('I can add the following provider:', async function(provider) { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + await cloudServicesEle.addProvider(provider); global.providers[provider.rows()[0][1]] = { serviceName: provider.rows()[0][1], }; }); -Then('I can see {string} provider', function(name) { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.waitForHasProvider(name).should.be.true; +Then('I can see {string} provider', async function(name) { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + const cloudServices = await cloudServicesEle.waitForHasProvider(name); + if (!cloudServices) { + throw new Error('Expected {string} provider to be visible'); + } }); -Then('I cannot see {string} provider', function(name) { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.waitForHasProvider(name, true).should.be.true; +Then('I cannot see {string} provider', async function(name) { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + const existingProvider = await cloudServicesEle.waitForHasProvider(name, true); + if (!existingProvider) { + throw new Error('Expected {string} provider visible'); + } }); -Then('I can edit {string} provider to:', function(currentName, newDetails) { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.editProvider(currentName, newDetails); +Then('I can edit {string} provider to:', async function(currentName, newDetails) { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + await cloudServicesEle.editProvider(currentName, newDetails); delete global.providers[currentName]; global.providers[newDetails.rows()[0][1]] = { serviceName: newDetails.rows()[0][1], }; }); -Then('I can delete {string} provider', function(name) { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.deleteProvider(name); +Then('I can delete {string} provider', async function(name) { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + await cloudServicesEle.deleteProvider(name); delete global.providers[name]; }); -When('I click the {string} pill', function(name) { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.clickElementName(name); +When('I click the {string} pill', async function(name) { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + await cloudServicesEle.clickElementName(name); }); -Given('Client {string} exists in clients', (clientId) => +Given('Client {string} exists in clients', async (clientId) => fixtures.clients.create({ 'entity-type': 'oauth2Client', id: clientId, @@ -74,40 +102,56 @@ Given('Client {string} exists in clients', (clientId) => }), ); -Then('I can see the nuxeo-cloud-consumers page', function() { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.nuxeoCloudConsumers.waitForVisible().should.be.true; -}); - -Then('I can add the following client:', function(client) { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.addClient(client); - global.clients[client.rows()[0][1]] = { +Then('I can see the nuxeo-cloud-consumers page', async function() { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + const NuxeoCloudConsumersPage = await cloudServicesEle.nuxeoCloudConsumers; + const NuxeoCloudConsumersPageIsVisible = await NuxeoCloudConsumersPage.waitForVisible(); + if (!NuxeoCloudConsumersPageIsVisible) { + throw new Error('Expected nuxeo-cloud-consumers page not be visible'); + } +}); + +Then('I can add the following client:', async function(client) { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + await cloudServicesEle.addClient(client); + global.clients[await client.rows()[0][1]] = { clientId: client.rows()[0][1], }; }); -Then('I can see {string} client', function(clientId) { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.waitForHasClient(clientId).should.be.true; +Then('I can see {string} client', async function(clientId) { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + const newClientID = await cloudServicesEle.waitForHasClient(clientId); + if (!newClientID) { + throw new Error('Expected {string} client not be visible'); + } }); -Then('I cannot see {string} client', function(clientId) { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.waitForHasClient(clientId, true).should.be.true; +Then('I cannot see {string} client', async function(clientId) { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + const existingClientEle = await cloudServicesEle.waitForHasClient(clientId, true); + if (!existingClientEle) { + throw new Error('Expected {string} client be visible'); + } }); -Then('I can edit {string} client to:', function(currentClientId, newDetails) { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.editClient(currentClientId, newDetails); +Then('I can edit {string} client to:', async function(currentClientId, newDetails) { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + await cloudServicesEle.editClient(currentClientId, newDetails); delete global.clients[currentClientId]; global.clients[newDetails.rows()[0][1]] = { clientId: newDetails.rows()[0][1], }; }); -Then('I can delete {string} client', function(clientId) { - this.ui.administration.cloudServices.waitForVisible(); - this.ui.administration.cloudServices.deleteClient(clientId); +Then('I can delete {string} client', async function(clientId) { + const cloudServicesEle = await this.ui.administration.cloudServices; + await cloudServicesEle.waitForVisible(); + await cloudServicesEle.deleteClient(clientId); delete global.clients[clientId]; }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/collections.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/collections.js index f894a4854e..c345400b97 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/collections.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/collections.js @@ -1,26 +1,69 @@ -import { Then } from '@cucumber/cucumber'; +import { Then } from '../../node_modules/@cucumber/cucumber'; -Then('I can see the {string} collection', function(name) { - this.ui.drawer.collections.waitForHasCollection(name).should.be.true; +Then('I can see the {string} collection', async function(name) { + const collection = await this.ui.drawer.collections.waitForHasCollection(name); + if (!collection) { + throw new Error(`Expected I can not click on the ${name} collection`); + } }); -Then('I can click on the {string} collection', function(name) { - this.ui.drawer.collections.select(name).should.be.true; + +Then('I can click on the {string} collection', async function(name) { + const myCollection = await this.ui.drawer; + const collectionsEle = await myCollection.collections; + const selectEle = await collectionsEle.select(name); + if (!selectEle) { + throw new Error(`Expected I can not click on the ${name} collection`); + } }); -Then('I can see that the document belongs to the collection', function() { - this.ui.browser.waitForHasChild(this.doc).should.be.true; + +Then('I can see that the document belongs to the collection', async function() { + const browser = await this.ui.browser; + const hasChild = await browser.waitForHasChild(this.doc); + if (!hasChild) { + throw new Error('Expected the document belongs to the collection not be visible'); + } }); -Then('I can click the document in the collection', function() { - this.ui.browser.clickChild(this.doc.title).should.be.true; + +Then('I can click the document in the collection', async function() { + const browserEle = await this.ui.browser; + const clickDocument = await browserEle.clickChild(this.doc.title); + if (!clickDocument) { + throw new Error('Expected I cannot click the document in the collection'); + } }); -Then('I can see the collection is in queue mode', function() { - this.ui.drawer.collections.isQueueMode.should.be.true; + +Then('I can see the collection is in queue mode', async function() { + const drawerEle = await this.ui.drawer; + const collectionsEle = await drawerEle.collections; + const isQueueModeEle = await collectionsEle.isQueueMode; + if (!isQueueModeEle) { + throw new Error('Expected the collection is in queue mode is not visible'); + } }); -Then('I can see the collection queue has the document', function() { - this.ui.drawer.collections.waitForHasMember(this.doc).should.be.true; + +Then('I can see the collection queue has the document', async function() { + const drawerEle = await this.ui.drawer; + const collectionsEle = await drawerEle.collections; + const hasMemberEle = await collectionsEle.waitForHasMember(this.doc); + if (!hasMemberEle) { + throw new Error('Expected the collection queue has the document is not visible'); + } }); -Then('I can remove the document from the collection queue', function() { - this.ui.drawer.collections.removeMember(this.doc).should.be.true; + +Then('I can remove the document from the collection queue', async function() { + const draweerEle = await this.ui.drawer; + const collectionsEle = await draweerEle.collections; + const removeMemberEle = await collectionsEle.removeMember(this.doc); + if (!removeMemberEle) { + throw new Error('Expected I can not remove the document from the collection queue'); + } }); -Then('I can see the collection queue does not have the document', function() { - this.ui.drawer.collections.waitForHasMember(this.doc, true).should.be.true; + +Then('I can see the collection queue does not have the document', async function() { + const drawerEle = await this.ui.drawer; + const collectionsEle = await drawerEle.collections; + const hasMemberEle = await collectionsEle.waitForHasMember(this.doc, true); + if (!hasMemberEle) { + throw new Error('Expected the collection queue does not have the document is not visible'); + } }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/comments.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/comments.js index 5f364597cf..38686f1354 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/comments.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/comments.js @@ -1,4 +1,4 @@ -import { Given, When, Then } from '@cucumber/cucumber'; +import { Given, When, Then } from '../../node_modules/@cucumber/cucumber'; Given('I have the following comment thread:', function(table) { /* @@ -25,110 +25,173 @@ Given(/([^\s']+)(?:'s)? comment "(.*)" has the following replies:/, (user, text, return comments.reduce((current, next) => current.then(next), Promise.resolve([])); }); -When(/I edit ([^\s']+)(?:'s)? comment "(.*)" with the following text: "(.*)"/, function(user, text, newText) { - this.ui.browser - .documentPage() - .comments.getComment(text, user === 'my' ? this.username : user) - .edit(); - this.ui.browser.documentPage().comments.writeComment(newText); - this.ui.browser.documentPage().comments.waitForNotVisible('.input-area iron-icon[name="submit"]'); -}); +When(/I edit ([^\s']+)(?:'s)? comment "(.*)" with the following text: "(.*)"/, async function(user, text, newText) { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); -When(/I expand the reply thread for ([^\s']+)(?:'s)? comment "(.*)"/, function(user, text) { - const link = this.ui.browser.documentPage().comments.getComment(text, user === 'my' ? this.username : user) - .summaryLink; - link.waitForVisible(); - link.scrollIntoView(); - link.click(); -}); + const comment = await currentComments.getComment(text, user === 'my' ? this.username : user); + await comment.edit(); -When('I load all comments', function() { - const link = this.ui.browser.documentPage().comments.loadMoreCommentsLink; - link.waitForVisible(); - link.scrollIntoView(); - link.click(); + await currentComments.writeComment(newText); + await currentComments.waitForNotVisible('.input-area iron-icon[name="submit"]'); }); -When(/I load all replies for ([^\s']+)(?:'s)? comment "(.*)"/, function(user, text) { - const comment = this.ui.browser.documentPage().comments.getComment(text, user === 'my' ? this.username : user); - const link = comment.thread.loadMoreCommentsLink; - link.waitForVisible(); - link.scrollIntoView(); - link.click(); -}); +When(/I expand the reply thread for ([^\s']+)(?:'s)? comment "(.*)"/, async function(user, text) { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); -When(/I remove ([^\s']+)(?:'s)? comment "(.*)"/, function(user, text) { - return this.ui.browser - .documentPage() - .comments.getComment(text, user === 'my' ? this.username : user) - .remove(); -}); + const comment = await currentComments.getComment(text, user === 'my' ? this.username : user); + const summaryLink = await comment.summaryLink; + await summaryLink.waitForVisible(); + await summaryLink.scrollIntoView(); + await summaryLink.click(); +}); -When(/I reply to ([^\s']+)(?:'s)? comment "(.*)" with the following text: "(.*)"/, function(user, text, reply) { - return this.ui.browser - .documentPage() - .comments.getComment(text, user === 'my' ? this.username : user) - .reply(reply); +When('I load all comments', async function() { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); + const link = await currentComments.loadMoreCommentsLink; + await link.waitForVisible(); + await link.scrollIntoView(); + await link.click(); }); -When('I write a comment with the following text: {string}', function(comment) { - return this.ui.browser.documentPage().comments.writeComment(comment); -}); +When(/I load all replies for ([^\s']+)(?:'s)? comment "(.*)"/, async function(user, text) { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); + + const comment = await currentComments.getComment(text, user === 'my' ? this.username : user); + const thread = await comment.thread; + await thread.waitForVisible(); + const link = await thread.loadMoreCommentsLink; + await link.waitForVisible(); + await link.scrollIntoView(); + await link.click(); +}); -Then('I can see the comment thread has {int} visible item(s)', function(nb) { - this.ui.browser.documentPage().comments.waitForVisible(); - driver.waitUntil(() => this.ui.browser.documentPage().comments.nbItems === nb); -}); +When(/I remove ([^\s']+)(?:'s)? comment "(.*)"/, async function(user, text) { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); -Then('I can see the comment thread has a total of {int} item(s) to be loaded', function(total) { - this.ui.browser.documentPage().comments.waitForVisible(); - const link = this.ui.browser.documentPage().comments.loadMoreCommentsLink; - link.waitForVisible(); - link.getText().should.be.equals(`View all ${total} comments`); + const comment = await currentComments.getComment(text, user === 'my' ? this.username : user); + const remove = await comment.remove(); + return remove; }); -Then("I can see document's comment thread", function() { - this.ui.browser.documentPage().comments.waitForVisible().should.be.true; +When(/I reply to ([^\s']+)(?:'s)? comment "(.*)" with the following text: "(.*)"/, async function(user, text, reply) { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); + + const comment = await currentComments.getComment(text, user === 'my' ? this.username : user); + const replyComment = await comment.reply(reply); + return replyComment; }); -Then(/I can see the reply thread for ([^\s']+)(?:'s)? comment "(.*)" has a total of (\d+) items to be loaded/, function( - user, - text, - total, -) { - const comment = this.ui.browser.documentPage().comments.getComment(text, user === 'my' ? this.username : user); - comment.thread.waitForVisible(); - const link = comment.thread.loadMoreCommentsLink; - link.waitForVisible(); - link.getText().should.be.equals(`View all ${total} replies`); +When('I write a comment with the following text: {string}', async function(comment) { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); + return currentComments.writeComment(comment); }); -Then(/I can see ([^\s']+)(?:'s)? comment: "(.*)"/, function(user, text) { - return this.ui.browser.documentPage().comments.getComment(text, user === 'my' ? this.username : user); +Then('I can see the comment thread has {int} visible item(s)', async function(nb) { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); + const nbItemLength = await currentComments.nbItems; + nbItemLength.should.be.equals(nb); }); -Then(/I can see ([^\s']+)(?:'s)? comment "(.*)" has (\d+) visible replies/, function(user, text, nb) { - const comment = this.ui.browser.documentPage().comments.getComment(text, user === 'my' ? this.username : user); - comment.thread.waitForVisible(); - comment.thread.nbItems.should.be.equals(nb); +Then('I can see the comment thread has a total of {int} item(s) to be loaded', async function(total) { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); + const link = await currentComments.loadMoreCommentsLink; + await link.waitForVisible(); + const linkText = await link.getText(); + linkText.should.be.equals(`View all ${total} comments`); }); -Then(/I can see ([^\s']+)(?:'s)? comment "(.*)" has a reply thread with (\d+) replies/, function(user, text, nb) { - const comment = this.ui.browser.documentPage().comments.getComment(text, user === 'my' ? this.username : user); - comment.summaryLink.waitForVisible(); - comment.summaryLink.getText().should.be.equals(`${nb} Replies`); +Then("I can see document's comment thread", async function() { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + const commentVisible = await currentComments.waitForVisible(); + commentVisible.should.be.true; }); -Then(/I (can|cannot) see the extended options available for ([^\s']+)(?:'s)? comment: "(.*)"/, function( +Then( + /I can see the reply thread for ([^\s']+)(?:'s)? comment "(.*)" has a total of (\d+) items to be loaded/, + async function(user, text, total) { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); + + const comment = await currentComments.getComment(text, user === 'my' ? this.username : user); + const thread = await comment.thread; + await thread.waitForVisible(); + const link = await thread.loadMoreCommentsLink; + await link.waitForVisible(); + const linkText = await link.getText(); + linkText.should.be.equals(`View all ${total} replies`); + }, +); + +Then(/I can see ([^\s']+)(?:'s)? comment: "(.*)"/, async function(user, text) { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); + const comment = await currentComments.getComment(text, user === 'my' ? this.username : user); + return comment; +}); + +Then(/I can see ([^\s']+)(?:'s)? comment "(.*)" has (\d+) visible replies/, async function(user, text, nb) { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); + + const comment = await currentComments.getComment(text, user === 'my' ? this.username : user); + const thread = await comment.thread; + await thread.waitForVisible(); + const nbItemLength = await thread.nbItems; + nbItemLength.should.be.equals(nb); +}); + +Then(/I can see ([^\s']+)(?:'s)? comment "(.*)" has a reply thread with (\d+) replies/, async function(user, text, nb) { + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); + + const comment = await currentComments.getComment(text, user === 'my' ? this.username : user); + const summaryLink = await comment.summaryLink; + await summaryLink.waitForVisible(); + const summaryText = await summaryLink.getText(); + summaryText.should.be.equals(`${nb} Replies`); +}); + +Then(/I (can|cannot) see the extended options available for ([^\s']+)(?:'s)? comment: "(.*)"/, async function( option, user, text, ) { option.should.to.be.oneOf(['can', 'cannot'], 'An unknown option was passed as argument'); - const comment = this.ui.browser.documentPage().comments.getComment(text, user === 'my' ? this.username : user); + const docPage = await this.ui.browser.documentPage(); + const currentComments = await docPage.comments; + await currentComments.waitForVisible(); + + const comment = await currentComments.getComment(text, user === 'my' ? this.username : user); + const commentOptions = await comment.options; + if (option === 'can') { - comment.options.isVisible().should.be.true; + const commentOptionsVisible = await commentOptions.isVisible(); + commentOptionsVisible.should.be.true; } else { - comment.options.isExisting().should.be.false; + const commentOptionsExist = await commentOptions.isExisting(); + commentOptionsExist.should.be.false; } }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/compare.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/compare.js index 7ae008c118..c5c3dab542 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/compare.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/compare.js @@ -1,8 +1,10 @@ -import { Then, When } from '@cucumber/cucumber'; +import { Then, When } from '../../node_modules/@cucumber/cucumber'; -When('I can click on the compare button', function() { - this.ui.browser.waitForVisible(); - this.ui.browser.selectionToolbar.compare.click(); +When('I can click on the compare button', async function() { + await this.ui.browser.waitForVisible(); + const toolbarEle = await this.ui.browser.selectionToolbar; + const compareEle = await toolbarEle.compare; + await compareEle.click(); }); Then('I can see compare document page is displayed', function() { diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/create_dialog.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/create_dialog.js index 153ee201e1..fdf11ca3a0 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/create_dialog.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/create_dialog.js @@ -1,78 +1,105 @@ -import { Then, When } from '@cucumber/cucumber'; +import { Then, When } from '../../node_modules/@cucumber/cucumber'; let currentDocType; let selectedTabName; -When('I click the Create Document button', function() { - this.ui.createButton.waitForVisible(); - this.ui.createButton.click(); +When('I click the Create Document button', async function() { + const createBtn = await this.ui.createButton; + await createBtn.waitForVisible(); + await createBtn.click(); }); -Then('I click the Create button to finish the import', function() { - const importButton = this.ui.createDialog.importCreateButton; - importButton.waitForVisible(); - importButton.waitForEnabled(); - importButton.click(); - driver.waitForExist('iron-overlay-backdrop', driver.options.waitForTimeout, true); - driver.pause(3000); // XXX just give it some time to the server to do the conversions +Then('I click the Create button to finish the import', async function() { + const createDialog = await this.ui.createDialog; + const importButton = await createDialog.importCreateButton; + await importButton.waitForVisible(); + await importButton.waitForEnabled(); + await driver.pause(5000); + await importButton.click(); + await driver.waitForExist('iron-overlay-backdrop', driver.options.waitForTimeout, true); + await driver.pause(3000); // XXX just give it some time to the server to do the conversions }); -Then(/^I go to the (.+) tab$/, function(name) { - const dialog = this.ui.createDialog; - dialog.waitForVisible(); - dialog.importTab(name).click(); +Then(/^I go to the (.+) tab$/, async function(name) { + const dialog = await this.ui.createDialog; + await dialog.waitForVisible(); + const importTab = await dialog.importTab(name); + await importTab.click(); }); -Then(/^I can see the (.+) tab content$/, function(name) { - const dialog = this.ui.createDialog; - dialog.waitForVisible(); - dialog.importPage(name).waitForVisible(); +Then(/^I can see the (.+) tab content$/, async function(name) { + const dialog = await this.ui.createDialog; + await dialog.waitForVisible(); + const importPage = await dialog.importPage(name); + await importPage.waitForVisible(); selectedTabName = name; }); -Then(/^I upload the (.+) on the tab content page$/, function(file) { - const dialog = this.ui.createDialog; - dialog.waitForVisible(); - dialog.upload(file, selectedTabName); - dialog.selectedFileToImport.waitForVisible(); +Then(/^I upload the (.+) on the tab content page$/, async function(file) { + const dialog = await this.ui.createDialog; + await dialog.waitForVisible(); + await dialog.upload(file, selectedTabName); + const fileToImport = await dialog.selectedFileToImport; + await fileToImport.waitForVisible(); }); -Then('I upload the following files on the tab content page:', function(table) { - const dialog = this.ui.createDialog; - dialog.waitForVisible(); - const docs = table.rows().map((row) => dialog.upload(row[0], selectedTabName)); - return docs.reduce((current, next) => current.then(next), Promise.resolve([])); +Then('I upload the following files on the tab content page:', async function(table) { + const dialog = await this.ui.createDialog; + await dialog.waitForVisible(); + const rows = await table.rows(); + const rowArray = Array.from(rows); + const docs = await rowArray.reduce(async (currentPromise, row) => { + const currentArray = await currentPromise; + const uploadedDoc = await dialog.upload(row[0], selectedTabName); + return [...currentArray, uploadedDoc]; + }, Promise.resolve([])); + return docs; }); -When('I select {word} from the Document Type menu', function(docType) { - this.ui.createDialog.waitForVisible(); - const button = this.ui.createDialog.documentCreate.getDoctypeButton(docType); - button.waitForVisible(); - button.click(); +When('I select {word} from the Document Type menu', async function(docType) { + const createDialogElem = await this.ui.createDialog; + await createDialogElem.waitForVisible(); + const docCreateElem = await createDialogElem.documentCreate; + const button = await docCreateElem.getDoctypeButton(docType); + await button.waitForVisible(); + await button.click(); currentDocType = docType; }); -When('I create a document with the following properties:', function(table) { - this.ui.createDialog.documentCreate.waitForVisible(); - this.ui.createDialog.documentCreate.layout(currentDocType).fillMultipleValues(table); - this.ui.createDialog.documentCreate.layout(currentDocType).getField('title').should.not.be.empty; - const title = this.ui.createDialog.documentCreate.layout(currentDocType).getFieldValue('title'); - this.ui.createDialog.createButton.waitForVisible(); - this.ui.createDialog.createButton.click(); - this.ui.browser.waitForNotVisible('iron-overlay-backdrop'); - this.ui.browser.hasTitle(title).should.be.true; +When('I create a document with the following properties:', async function(table) { + const createDialogElem = await this.ui.createDialog; + const docCreateEle = await createDialogElem.documentCreate; + const layout = await docCreateEle.layout(currentDocType); + await layout.fillMultipleValues(table); + const field = await layout.getField('title'); + field.should.not.be.empty; + const title = await layout.getFieldValue('title'); + const button = await createDialogElem.createButton; + await button.waitForVisible(); + await button.click(); + const browser = await this.ui.browser; + await browser.waitForNotVisible('iron-overlay-backdrop'); + const hasTitle = await browser.hasTitle(title); + hasTitle.should.be.true; this.doc = { type: currentDocType, title }; }); -Then('I see the {word} page', function(docType) { - this.ui.browser.waitForNotVisible('iron-overlay-backdrop'); - this.ui.browser.documentPage(docType).view.waitForVisible(); +Then('I see the {word} page', async function(docType) { + const ele = await this.ui.browser; + await ele.waitForNotVisible('iron-overlay-backdrop'); + const docPage = await ele.documentPage(docType); + const docPageView = await docPage.view; + await docPageView.waitForVisible(); }); -Then(/^I can see that a document of the type (.+) and title (.+) is created$/, function(docType, title) { +Then(/^I can see that a document of the type (.+) and title (.+) is created$/, async function(docType, title) { this.ui.browser.waitForNotVisible('iron-overlay-backdrop'); - this.ui.browser.documentPage(docType).view.waitForVisible(); + const documentPage = await this.ui.browser.documentPage(docType); + const docView = await documentPage.view; + await docView.waitForVisible(); + await driver.pause(2000); currentDocType = docType; - this.ui.browser.hasTitle(title).should.be.true; + const docTitle = await this.ui.browser.hasTitle(title); + await docTitle.should.be.true; this.doc = { type: currentDocType, title }; }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/csv-import.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/csv-import.js new file mode 100644 index 0000000000..9b1097ccd1 --- /dev/null +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/csv-import.js @@ -0,0 +1,33 @@ +import { When } from '../../node_modules/@cucumber/cucumber'; + +/** + * Import the csv file + * + * @deprecated since 3.0.3. Please use "I upload the (.+) on the tab content page" located in create_dialog.js + * */ +When(/^I import the (.+) file$/, async function(file) { + const dialog = await this.ui.createDialog; + await dialog.waitForVisible(); + await dialog.setFileToImport(file); + const selectedFileToImport = await dialog.selectedFileToImport; + const selectVisible = await selectedFileToImport.waitForVisible(); + await selectVisible.should.be.true; + const importcb = await dialog.importCSVButton; + await importcb.click(); + const importSuccess = await dialog.importSuccess; + await importSuccess.waitForVisible(); + const importCloseButton = await dialog.importCloseButton; + await importCloseButton.waitForVisible(); + await importCloseButton.click(); +}); + +When('I can see that the csv file is imported with no errors', function() { + const dialog = this.ui.createDialog; + dialog.waitForVisible(); + dialog.selectedCSVToImport.waitForVisible().should.be.true; + dialog.importCSVButton.click(); + dialog.importSuccess.waitForVisible(); + dialog.importError.isVisible().should.be.false; + dialog.importCloseButton.waitForVisible(); + dialog.importCloseButton.click(); +}); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/doc_suggestion.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/doc_suggestion.js index 51dd34da32..ce4bf642ef 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/doc_suggestion.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/doc_suggestion.js @@ -1,11 +1,11 @@ -import { Then } from '@cucumber/cucumber'; +import { Then } from '../../node_modules/@cucumber/cucumber'; -Then('I can navigate to the document selected in the {string} single document suggestion widget', function(name) { - this.ui.browser - .documentPage('DocSuggestion') - .metadata.layout() - .getField(name) - .element('.selectivity-single-selected-item') - .element('a') - .click(); +Then('I can navigate to the document selected in the {string} single document suggestion widget', async function(name) { + const docpageEle = await this.ui.browser.documentPage('DocSuggestion'); + const docmetaEle = await docpageEle.metadata; + const layoutEle = await docmetaEle.layout(); + const fieldEle = await layoutEle.getField(name); + const singleItemELe = await fieldEle.element('.selectivity-single-selected-item'); + const elementEx = await singleItemELe.element('a'); + elementEx.click(); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/document.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/document.js index 0a12124418..307aebdf3e 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/document.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/document.js @@ -1,13 +1,15 @@ -import { Given, When, Then } from '@cucumber/cucumber'; +/* eslint-disable no-await-in-loop */ +import { Given, When, Then } from '../../node_modules/@cucumber/cucumber'; import { url } from '../../pages/helpers'; -Given('I have a {word} document', function(docType) { +Given('I have a {word} document', async function(docType) { docType = docType || 'File'; - const doc = fixtures.documents.init(docType); + const doc = await fixtures.documents.init(docType); // create the document - return fixtures.documents.create(this.doc.path || '/default-domain', doc).then((d) => { + const createDoc = await fixtures.documents.create(this.doc.path || '/default-domain', doc).then((d) => { this.doc = d; }); + return createDoc; }); Given(/^I have a document imported from file "(.+)"$/, function(mimeType) { @@ -16,16 +18,18 @@ Given(/^I have a document imported from file "(.+)"$/, function(mimeType) { }); }); -Given(/^I have permission (\w+) for this document$/, function(permission) { - return fixtures.documents.setPermissions(this.doc, permission, this.username).then((d) => { +Given(/^I have permission (\w+) for this document$/, async function(permission) { + const setPermission = await fixtures.documents.setPermissions(this.doc, permission, this.username).then((d) => { this.doc = d; }); + return setPermission; }); -Given(/^I have permission (\w+) for the document with path "(.+)"$/, function(permission, path) { - return fixtures.documents.setPermissions(path, permission, this.username).then((d) => { +Given(/^I have permission (\w+) for the document with path "(.+)"$/, async function(permission, path) { + const setPermission = await fixtures.documents.setPermissions(path, permission, this.username).then((d) => { this.doc = d; }); + return setPermission; }); Given(/^I have the following permissions to the documents$/, function(table) { @@ -38,26 +42,24 @@ Given(/^This document has a (major|minor) version$/, function(versionType) { }); }); -Given(/^I have a document added to "([^"]*)" collection$/, function(colName) { +Given(/^I have a document added to "([^"]*)" collection$/, async function(colName) { const docFile = fixtures.documents.init('File'); // create the document - return fixtures.documents - .create(this.doc.path, docFile) - .then((doc) => fixtures.collections.addToNewCollection(doc, colName)) - .then((d) => { - this.doc = d; - }); + const doc = await fixtures.documents.create(this.doc.path, docFile); + const updatedDoc = await fixtures.collections.addToNewCollection(doc, colName); + this.doc = updatedDoc; }); -Given(/^This document has a "([^"]*)" workflow running$/, function(workflowName) { - return fixtures.workflows.start(this.doc, workflowName, this.username).then((workflowInstance) => { +Given(/^This document has a "([^"]*)" workflow running$/, async function(workflowName) { + const workflow = await fixtures.workflows.start(this.doc, workflowName, this.username).then((workflowInstance) => { this.workflowInstance = workflowInstance; }); + return workflow; }); Given( /^The workflow running for this document will proceed with "([^"]*)" action and the following variables:$/, - function(action, table) { + async function(action, table) { this.workflowInstance.should.not.be.undefined; return this.workflowInstance.fetchTasks().then((tasks) => { tasks.entries.length.should.be.equal(1); @@ -83,11 +85,12 @@ Given( }, ); -Given(/^This document has file "(.+)" for content$/, function(file) { - return fixtures.documents.attach(this.doc, fixtures.blobs.get(file)); +Given(/^This document has file "(.+)" for content$/, async function(file) { + const contentEle = await fixtures.documents.attach(this.doc, fixtures.blobs.get(file)); + return contentEle; }); -Given(/^This document has file "(.+)" for attachment/, function(file) { +Given(/^This document has file "(.+)" for attachment/, async function(file) { return fixtures.documents.attach(this.doc, fixtures.blobs.get(file), true); }); @@ -100,242 +103,308 @@ Given(/^I have a (.+) Note$/, function(format) { }); }); -When(/^I browse to the document$/, function() { - this.ui.browser.browseTo(this.doc.path); +When(/^I browse to the document$/, async function() { + await driver.pause(3000); + const path = await this.doc.path; + await driver.pause(1000); + await this.ui.browser.browseTo(path); }); -When(/^I browse to the "(.*)" document page$/, function(page) { - this.ui.browser.browseTo(`${this.doc.path}?p=${page}`); +When(/^I browse to the "(.*)" document page$/, async function(page) { + await this.ui.browser.browseTo(`${this.doc.path}?p=${page}`); }); -When(/^I browse to the document with path "(.+)"$/, function(path) { - this.ui.browser.browseTo(path); +When(/^I browse to the document with path "(.+)"$/, async function(path) { + await driver.pause(2000); + const browser = await this.ui.browser; + await browser.browseTo(path); }); -Then('I navigate to {string} child', function(title) { - this.ui.browser.clickChild(title); +Then('I navigate to {string} child', async function(title) { + const browser = await this.ui.browser; + const child = await browser.clickChild(title); + if (!child) { + throw Error(`child should have ${title} title`); + } }); -When(/^I start a (.+)$/, function(workflow) { - this.ui.browser.startWorkflow(workflow); +When(/^I start a (.+)$/, async function(workflow) { + await this.ui.browser.startWorkflow(workflow); }); -When(/^I click the process button$/, function() { - const { processWorkflowButton } = this.ui.browser.documentPage(); - processWorkflowButton.waitForVisible(); - processWorkflowButton.click(); +When(/^I click the process button$/, async function() { + const documentPage = await this.ui.browser.documentPage(); + const documentPageInfo = await documentPage.info; + await documentPageInfo.waitForVisible(); + const processButton = await documentPage.processWorkflowButton; + await processButton.waitForVisible(); + await processButton.click(); }); -Then(/^I can't view the document$/, function() { +Then(/^I can't view the document$/, async function() { url(`#!/browse${this.doc.path}`); - this.ui.browser.breadcrumb.waitForVisible(browser.options.waitforTimeout, true).should.be.true; + const breadcumbEle = await this.ui.browser.breadcrumb; + const isVisible = await breadcumbEle.waitForVisible(browser.options.waitforTimeout, true); + isVisible.should.be.true; }); Then("I can see the document's title", function() { this.ui.browser.title.waitForVisible(); }); -Then(/I can see (.+) metadata with the following properties:/, function(docType, table) { - this.ui.browser.documentPage(docType).waitForVisible(); - this.ui.browser.documentPage(docType).metadata.waitForVisible(); - table.rows().forEach((row) => { - this.ui.browser - .documentPage(docType) - .metadata.layout() - .waitForVisible(); - if (row[0] === 'subjects') { - driver.waitUntil( - () => - this.ui.browser - .documentPage(docType) - .metadata.layout() - .getFieldValue(row[0]) - .indexOf(row[1]) > -1, - ); +Then(/I can see (.+) metadata with the following properties:/, async function(docType, table) { + const browser = await this.ui.browser; + const docPage = await browser.documentPage(docType); + await docPage.waitForVisible(); + const docMeta = await docPage.metadata; + await docMeta.waitForVisible(); + const tableRows = await table.rows; + for (let i = 0; i < tableRows.length; i++) { + const tableRow = tableRows[i]; + const docLayout = await docMeta.layout(); + await docLayout.waitForVisible(); + if (tableRow[0] === 'subjects') { + const docField = await docLayout.getFieldValue(tableRow[0]); + (await docField.indexOf(tableRow[1])) > -1; } else { - driver.waitUntil( - () => - this.ui.browser - .documentPage(docType) - .metadata.layout() - .getFieldValue(row[0]) - .toString() === row[1], - ); + const docFiel = await docLayout.getFieldValue(tableRow[0]); + (await docFiel.toString()) === tableRow[1]; } - }); -}); - -Then(/^I can't edit the document metadata$/, function() { - this.ui.browser.editButton.waitForVisible(browser.options.waitforTimeout, true).should.be.true; -}); - -Then(/^I can edit the (.*) metadata$/, function(docType) { - const { browser } = this.ui; - browser.editButton.waitForVisible(); - browser.editButton.click(); - const form = browser.editForm(docType); - form.waitForVisible(); - form.title = docType; - form.save(); - driver.waitForExist('iron-overlay-backdrop', driver.options.waitForTimeout, true); -}); - -Then(/^I can edit the following properties in the (.+) metadata:$/, function(docType, table) { - const { browser } = this.ui; - browser.editButton.waitForVisible(); - browser.editButton.click(); - const form = browser.editForm(docType); - form.waitForVisible(); - form.layout.waitForVisible(); - form.layout.fillMultipleValues(table); - form.save(); -}); - -Then(/^I can't edit the Note$/, function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.view.waitForVisible(); - page.view.noteEditor.waitForVisible(); - page.view.noteEditor.editButton.waitForVisible(browser.options.waitforTimeout, true).should.be.true; + } }); -Then(/^I can edit the (.*) Note$/, function(format) { - const page = this.ui.browser.documentPage(this.doc.type); - page.view.waitForVisible(); - +Then(/^I can't edit the document metadata$/, async function() { + const editButtonEle = await this.ui.browser.editButton; + const isVisible = await editButtonEle.waitForVisible(browser.options.waitforTimeout, true); + isVisible.should.be.true; +}); + +Then(/^I can edit the (.*) metadata$/, async function(docType) { + const browser = await this.ui.browser; + const browserEditButton = await browser.editButton; + await browserEditButton.waitForVisible(); + await browserEditButton.click(); + const form = await browser.editForm(docType); + await form.waitForVisible(); + const inputElement = await form.el.element('.input-element input'); + await fixtures.layouts.setValue(inputElement, docType); + await form.save(); + await driver.waitForExist('iron-overlay-backdrop', driver.options.waitForTimeout, true); +}); + +Then(/^I can edit the following properties in the (.+) metadata:$/, async function(docType, table) { + const browser = await this.ui.browser; + const button = await browser.editButton; + await button.waitForVisible(); + await button.click(); + const form = await browser.editForm(docType); + await form.waitForVisible(); + await form.layout.waitForVisible(); + await form.layout.fillMultipleValues(table); + await form.save(); +}); + +Then(/^I can't edit the Note$/, async function() { + const browser = await this.ui.browser; + const page = await browser.documentPage(this.doc.type); + const view = await page.view; + const noteEditor = await view.noteEditor; + const editButtonEle = await noteEditor.editButton; + await editButtonEle.waitForVisible(driver.options.waitforTimeout, true); +}); + +Then(/^I can edit the (.*) Note$/, async function(format) { + const page = await this.ui.browser.documentPage(this.doc.type); + const view = await page.view; + await view.waitForVisible(); + const previewEle = await view.preview; + const noteEditor = await view.noteEditor; const newContent = `NEW ${format} CONTENT`; switch (format) { case 'HTML': - page.view.noteEditor.waitForVisible(); - page.view.noteEditor.setContent(newContent); - page.view.noteEditor.save(); - driver.waitUntil(() => page.view.noteEditor.hasContent(`

${newContent}

`)); + await noteEditor.waitForVisible(); + await noteEditor.setContent(newContent); + await noteEditor.save(); + await driver.waitUntil(async () => noteEditor.hasContent(`

${newContent}

`), { + timeoutMsg: 'step definition document 230', + }); break; case 'XML': case 'Markdown': case 'Text': - page.view.noteEditor.waitForVisible(); - page.view.noteEditor.edit(); - page.view.noteEditor.textarea.waitForVisible(); - page.view.noteEditor.textarea.setValue(newContent); - page.view.noteEditor.save(); - page.view.preview.waitForVisible(); - driver.waitUntil(() => { - try { - let elContent; - if (format === 'XML') { - elContent = page.view.preview.element('#xml'); - } else if (format === 'Text') { - elContent = page.view.preview.element('#plain'); - } else { - elContent = page.view.preview.element('marked-element #content'); + await noteEditor.waitForVisible(); + await noteEditor.edit(); + await noteEditor.textarea.waitForVisible(); + await noteEditor.textarea.setValue(newContent); + await noteEditor.save(); + await previewEle.waitForVisible(); + await driver.waitUntil( + async () => { + try { + let elContent; + if (format === 'XML') { + elContent = await previewEle.$('#xml'); + } else if (format === 'Text') { + elContent = await previewEle.$('#plain'); + } else { + elContent = await previewEle.$('marked-element #content'); + } + const elementContentVisible = await elContent.isVisible(); + const elementContentText = await elContent.getText(); + const elContentEle = elementContentVisible && elementContentText === newContent; + return elContentEle; + } catch (e) { + return false; } - return elContent.isVisible() && elContent.getText() === newContent; - } catch (e) { - return false; - } - }); + }, + { + timeoutMsg: 'step definition document 260', + }, + ); break; default: // do nothing } }); -Then('I add the document to the {string} collection', function(name) { - this.ui.browser.addToCollection(name); +Then('I add the document to the {string} collection', async function(name) { + const browser = await this.ui.browser; + await browser.addToCollection(name); }); -Then('I can see the document belongs to the {string} collection', function(name) { - this.ui.browser.hasCollection(name).should.be.true; +Then('I can see the document belongs to the {string} collection', async function(name) { + await driver.pause(3000); + const browser = await this.ui.browser; + const hasCollection = await browser.hasCollection(name); + if (!hasCollection) { + throw new Error(`Expected the document belongs to the ${name} that is not visible`); + } }); -Then('I can delete the document from the {string} collection', function(name) { - this.ui.browser.removeFromCollection(name); +Then('I can delete the document from the {string} collection', async function(name) { + const deleteCollection = await this.ui.browser; + await deleteCollection.removeFromCollection(name); }); -Then('I can see the document does not belong to the {string} collection', function(name) { - this.ui.browser.doesNotHaveCollection(name).should.be.true; +Then('I can see the document does not belong to the {string} collection', async function(name) { + const browserEle = await this.ui.browser; + const doesNotHaveCollection = await browserEle.doesNotHaveCollection(name); + if (!doesNotHaveCollection) { + throw new Error('Expected the document does not belong to the {string} collection is not visible'); + } }); -Then('I add the document to the favorites', function() { - this.ui.browser.addToFavorites(); +Then('I add the document to the favorites', async function() { + await this.ui.browser.addToFavorites(); }); -Then('I can see the document has {int} children', function(nb) { - this.ui.browser.waitForNbChildren(nb); +Then('I can see the document has {int} children', async function(nb) { + await driver.pause(2000); + const browser = await this.ui.browser; + const countOut = await browser.waitForNbChildren(nb); + if (countOut !== nb) { + throw Error(`Document should have ${nb} children but found ${countOut}`); + } }); -Then(/^I can see a process is running in the document$/, function() { - const documentPage = this.ui.browser.documentPage(); +Then(/^I can see a process is running in the document$/, async function() { + const documentPage = await this.ui.browser.documentPage(); // check info bar in the document is visible - documentPage.infoBar.waitForVisible(); + const infoBar = await documentPage.infoBar; + await infoBar.waitForVisible(); // assert that info bar displays a task is running - documentPage.taskInfo.waitForVisible(); + const taskInfo = await documentPage.taskInfo; + await taskInfo.waitForVisible(); // assert that there's a button to process the task - documentPage.processWorkflowButton.waitForVisible(); + const processWorkflowButton = await documentPage.processWorkflowButton; + await processWorkflowButton.waitForVisible(); // assert that document info says a process is running - documentPage.info.waitForVisible(); - documentPage.info.waitForVisible('[name="process"]'); + const documentPageInfo = await documentPage.info; + await documentPageInfo.waitForVisible(); + await documentPageInfo.$('[name="process"]').waitForVisible(); }); -Then(/^I can see a process is not running in the document$/, function() { - const documentPage = this.ui.browser.documentPage(); +Then(/^I can see a process is not running in the document$/, async function() { + const documentPage = await this.ui.browser.documentPage(); // check info bar in the document is not visible - documentPage.infoBar.isVisible().should.be.false; + const infoBar = await documentPage.infoBar; + const infoBarVisible = await infoBar.isVisible(); + infoBarVisible.should.be.false; }); -Then(/^I cannot start a workflow$/, function() { - this.ui.browser.startWorkflowButton.isExisting().should.be.false; +Then(/^I cannot start a workflow$/, async function() { + const button = await this.ui.browser.startWorkflowButton; + const isButtonExisting = await button.isExisting(); + isButtonExisting.should.be.false; }); -Then(/^I can abandon the workflow$/, function() { - const { abandonWorkflowButton } = this.ui.browser.documentPage(); - abandonWorkflowButton.waitForVisible(); - abandonWorkflowButton.click(); - driver.alertAccept(); - const documentPage = this.ui.browser.documentPage(); +Then(/^I can abandon the workflow$/, async function() { + const documentPage = await this.ui.browser.documentPage(); + const abandonWorkflowButton = await documentPage.abandonWorkflowButton; + await abandonWorkflowButton.waitForVisible(); + await abandonWorkflowButton.click(); + await driver.alertAccept(); // check info bar in the document is not visible - documentPage.infoBar.waitForVisible(browser.options.waitforTimeout, true); + const infoBar = await documentPage.infoBar; + await infoBar.waitForVisible(browser.options.waitforTimeout, true); // assert that info bar displays a task is running - documentPage.taskInfo.waitForVisible(browser.options.waitforTimeout, true); + const taskInfo = await documentPage.taskInfo; + await taskInfo.waitForVisible(browser.options.waitforTimeout, true); // assert that document info says a process is running - documentPage.info.waitForVisible(); - documentPage.info.waitForVisible('[name="process"]', browser.options.waitforTimeout, true); + const docPageInfo = await documentPage.info; + await docPageInfo.waitForVisible(); + await docPageInfo.waitForVisible('[name="process"]', browser.options.waitforTimeout, true); // In order to avoid errors when performing the teardown - fixtures.workflows.removeInstance(this.workflowInstance.id); -}); - -Then(/^I can see the document is a publication$/, function() { - const infoBar = this.ui.browser.publicationInfobar; - infoBar.waitForVisible(); -}); - -Then(/^I can unpublish the document$/, function() { - const unpublishButton = this.ui.browser.publicationInfobar.element('nuxeo-unpublish-button'); - unpublishButton.waitForVisible(); - unpublishButton.click(); - const unpublishConfirm = unpublishButton.element('nuxeo-confirm-button #dialog paper-button[class="primary"]'); - unpublishConfirm.waitForVisible(); - unpublishConfirm.click(); -}); - -Then('I can see {int} validation error(s) in the {string} edit form', function(nbErrors, docType) { - const { browser } = this.ui; - const form = browser.editForm(docType); - form.waitForVisible(); - driver.waitUntil( - () => form.errorMessages.length === nbErrors, - `Expecting to get ${nbErrors} results but found ${form.errorMessages.length}`, + await fixtures.workflows.removeInstance(this.workflowInstance.id); +}); + +Then(/^I can see the document is a publication$/, async function() { + const browser = await this.ui.browser; + const infoBar = await browser.publicationInfobar; + await infoBar.waitForVisible(); +}); + +Then(/^I can unpublish the document$/, async function() { + const browser = await this.ui.browser; + const infoBar = await browser.publicationInfobar; + const unpublishButton = await infoBar.element('nuxeo-unpublish-button'); + await unpublishButton.waitForVisible(); + await unpublishButton.click(); + const unpublishConfirm = await unpublishButton.$('nuxeo-confirm-button #dialog paper-button[class="primary"]'); + await unpublishConfirm.waitForVisible(); + await unpublishConfirm.click(); +}); + +Then('I can see {int} validation error(s) in the {string} edit form', async function(nbErrors, docType) { + const browser = await this.ui.browser; + const form = await browser.editForm(docType); + await form.waitForVisible(); + await driver.waitUntil( + async () => { + await driver.pause(1000); + const errorMessages = await form.errorMessages; + return errorMessages.length === nbErrors; + }, + { + timeout: 5000, + timeoutMsg: `Expecting to get ${nbErrors} results but found ${form.errorMessages.length}`, + }, ); }); -Then('I can see the {string} error message in the {string} edit form', function(message, docType) { - const { browser } = this.ui; - const form = browser.editForm(docType); - form.waitForVisible(); - driver.waitUntil( - () => form.errorMessages.some((err) => err === message), - `Expecting to find '${message}' error message but not found`, - ); +Then('I can see the {string} error message in the {string} edit form', async function(message, docType) { + const { browser } = await this.ui; + try { + const form = await browser.editForm(docType); + await form.waitForVisible(); + const errorMessages = await form.errorMessages; + const hasErrorMessage = errorMessages.some((err) => err === message); + if (!hasErrorMessage) { + throw new Error(`Expecting to find '${message}' error message but not found`); + } + } catch (error) { + console.error(error.message); + } }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/favorites.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/favorites.js index 4aaa061576..47a366a8a9 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/favorites.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/favorites.js @@ -1,9 +1,12 @@ -import { Then } from '@cucumber/cucumber'; +import { Then } from '../../node_modules/@cucumber/cucumber'; -Then('I can see the document belongs to the favorites', function() { - this.ui.drawer.favorites.hasDocument(this.doc).should.be.true; +Then('I can see the document belongs to the favorites', async function() { + const drawerEle = await this.ui.drawer; + const favEle = await drawerEle.favorites; + await favEle.hasDocument(this.doc); }); -Then('I can remove the document from the favorites', function() { - this.ui.drawer.favorites.removeDocument(this.doc).should.be.true; +Then('I can remove the document from the favorites', async function() { + const drawerEle = await this.ui.drawer; + await drawerEle.favorites.removeDocument(this.doc); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/group.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/group.js index 8324a78d5e..f8ac75d0de 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/group.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/group.js @@ -1,62 +1,83 @@ -import { Then, When } from '@cucumber/cucumber'; +import { Then, When } from '../../node_modules/@cucumber/cucumber'; -When(/^I select group from the dropdown menu$/, function() { - this.ui.group.dropdown.waitForVisible(); - this.ui.group.groupItem.click(); +When(/^I select group from the dropdown menu$/, async function() { + const groupDropEle = await this.ui.group.dropdown; + await groupDropEle.waitForVisible(); + const groupItemEle = await this.ui.group.groupItem; + groupItemEle.click(); }); -When(/^I can see the new group form$/, function() { - this.ui.group.createGroupForm.waitForVisible(); +When(/^I can see the new group form$/, async function() { + const groupFormEle = await this.ui.group.createGroupForm; + await groupFormEle.waitForVisible(); }); -Then(/^I can create a group with the following properties:$/, function(table) { - this.ui.group.fillMultipleValues(table); - this.ui.group.createGroupButton.click(); +Then(/^I can create a group with the following properties:$/, async function(table) { + const groupELe = this.ui.group; + await groupELe.fillMultipleValues(table); + const groupButtonEle = await groupELe.createGroupButton; + groupButtonEle.click(); }); Then(/^I can search for the following groups$/, function(table) { - table.rows().forEach((row) => { - this.ui.group.searchFor(row[0]); - this.ui.group.searchResult(row[0]).waitForVisible().should.be.true; - this.ui.group.waitForVisible('nuxeo-card[name="groups"] .table nuxeo-group-tag'); - this.ui.group.click('nuxeo-card[name="groups"] .table nuxeo-group-tag'); + table.rows().forEach(async (row) => { + await this.ui.group.searchFor(row[0]); + const resultEle = await this.ui.group.searchResult(row[0]); + const visible = await resultEle.waitForVisible(); + if (!visible) { + throw new Error('Result not found'); + } + await this.ui.group.waitForVisible('nuxeo-card[name="groups"] .table nuxeo-group-tag'); + await this.ui.group.click('nuxeo-card[name="groups"] .table nuxeo-group-tag'); this.ui.group.waitForVisible('nuxeo-group-management'); const group = this.ui.group.el.elements('.header .groupname').find((e) => e.getText() === row[0]); group.waitForVisible().should.be.true; }); }); -Then(/^I can edit the following groups$/, function(table) { - table.rows().forEach((row) => { - this.ui.group.searchFor(row[0]); - driver.waitUntil(() => { - // XXX horrible temporary workaround for stale element when clicking the result (see NXP-27621) - try { - const result = this.ui.group.searchResult(row[0]); - result.waitForVisible(); - result.click(); - return true; - } catch (e) { - return false; - } - }); - this.ui.group.editGroupButton.waitForVisible(); - this.ui.group.editGroupButton.click(); - fixtures.layouts.setValue(this.ui.group.editGroupLabel, row[1]); - this.ui.group.editGroupDialogButton.waitForVisible(); - this.ui.group.editGroupDialogButton.click(); - browser.back(); +Then(/^I can edit the following groups$/, async function(table) { + await table.rows().forEach(async (row) => { + await this.ui.group.searchFor(row[0]); + await driver.waitUntil( + async () => { + // XXX horrible temporary workaround for stale element when clicking the result (see NXP-27621) + try { + const result = await this.ui.group.searchResult(row[0]); + await result.waitForVisible(); + await result.click(); + return true; + } catch (e) { + return false; + } + }, + { + timeoutMsg: 'edit following groups timedout', + }, + ); + const editgroup = await this.ui.group; + const editgroupbutton = await editgroup.editGroupButton; + await editgroupbutton.waitForVisible(); + await editgroupbutton.click(); + await fixtures.layouts.setValue(this.ui.group.editGroupLabel, row[1]); + const editDialogEle = await editgroup.editGroupDialogButton; + await editDialogEle.waitForVisible(); + await editDialogEle.click(); + await browser.back(); }); }); -Then(/^I can delete the following groups$/, function(table) { - table.rows().forEach((row) => { - this.ui.group.searchFor(row[0]); - this.ui.group.searchResult(row[0]).waitForVisible(); - this.ui.group.searchResult(row[0]).click(); - this.ui.group.deleteGroupButton.waitForVisible(); - this.ui.group.deleteGroupButton.click(); - this.ui.group.confirmDeleteGroupButton.waitForVisible(); - this.ui.group.confirmDeleteGroupButton.click(); +Then(/^I can delete the following groups$/, async function(table) { + await table.rows().forEach(async (row) => { + const group = await this.ui.group; + await group.searchFor(row[0]); + const searchResultEle = await group.searchResult(row[0]); + await searchResultEle.waitForVisible(); + await searchResultEle.click(); + const deleteEle = await group.deleteGroupButton; + await deleteEle.waitForVisible(); + await deleteEle.click(); + const confirmEle = await group.confirmDeleteGroupButton; + await confirmEle.waitForVisible(); + await confirmEle.click(); }); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/history.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/history.js index 1f141095a6..6cf777f0e8 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/history.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/history.js @@ -1,13 +1,24 @@ -import { Then } from '@cucumber/cucumber'; +import { Then } from '../../node_modules/@cucumber/cucumber'; -Then('I can see the history table', function() { - this.ui.historyTable.isHistoryTableVisible.should.be.true; +Then('I can see the history table', async function() { + const historyTable = await this.ui.historyTable; + const isHistoryTableDisplayed = await historyTable.isHistoryTableVisible; + if (!isHistoryTableDisplayed) { + throw new Error('History Table not found'); + } }); -Then('I have a non empty history table', function() { - this.ui.historyTable.isHistoryTableFilled.should.be.true; +Then('I have a non empty history table', async function() { + const historyTable = await this.ui.historyTable; + const isTableFilled = await historyTable.isHistoryTableFilled; + + if (!isTableFilled) { + throw new Error('History Table not found'); + } }); -Then('I can see {string} entry in history table', function(performedAction) { - this.ui.historyTable.waitForHasEntry(performedAction).should.be.true; +Then('I can see {string} entry in history table', async function(performedAction) { + const historyTable = await this.ui.historyTable; + const hasEntry = await historyTable.waitForHasEntry(performedAction); + hasEntry.should.be.true; }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/home.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/home.js index 5dc614c3e2..f0a52bd1ab 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/home.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/home.js @@ -1,13 +1,17 @@ -import { Then, When } from '@cucumber/cucumber'; +import { Then, When } from '../../node_modules/@cucumber/cucumber'; -When('I click the Nuxeo logo', function() { - return this.ui.goHome(); +When('I click the Nuxeo logo', async function() { + const home = await this.ui.goHome(); + return home; }); -Then('I can see my home', function() { - this.ui.home.waitForVisible().should.be.true; +Then('I can see my home', async function() { + const check = await this.ui.home.waitForVisible(); + check.should.be.true; }); -Then('I have a {string} card', function(title) { - this.ui.home.card(title).waitForVisible().should.be.true; +Then('I have a {string} card', async function(title) { + const card = await this.ui.home.card(title); + const visi = await card.waitForVisible(); + visi.should.be.true; }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/import_dialog.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/import_dialog.js index 0cf85c0227..32350f59e1 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/import_dialog.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/import_dialog.js @@ -1,27 +1,36 @@ -import { Then, When } from '@cucumber/cucumber'; +import { Then, When } from '../../node_modules/@cucumber/cucumber'; -When('I click on Add Properties button', function() { - this.ui.createDialog.addProperties.waitForVisible(); - this.ui.createDialog.addProperties.click(); +When('I click on Add Properties button', async function() { + const createDialog = await this.ui.createDialog; + const addProperties = await createDialog.addProperties; + await addProperties.waitForVisible(); + await addProperties.click(); }); -Then('I select {string} asset type', function(val) { - this.ui.createDialog.selectAnAssetType.waitForVisible(); - this.ui.createDialog.selectAnAssetType.click(); - this.ui.createDialog.selectAssetType(val); +Then('I select {string} asset type', async function(val) { + const createDialog = await this.ui.createDialog; + const assetType = await createDialog.selectAnAssetType; + await assetType.waitForVisible(); + await assetType.click(); + await createDialog.selectAssetType(val); }); -Then('I click the Create button to complete the import', function() { - const importButton = this.ui.createDialog.importCreateButtonProperties; - importButton.waitForVisible(); - importButton.waitForEnabled(); - importButton.click(); +Then('I click the Create button to complete the import', async function() { + const createDialog = await this.ui.createDialog; + const importButton = await createDialog.importCreateButtonProperties; + await importButton.waitForVisible(); + await importButton.waitForEnabled(); + await importButton.click(); }); -Then('I add the following properties:', function(table) { - this.ui.createDialog.documentImportLayout.fillMultipleValues(table); +Then('I add the following properties:', async function(table) { + const createDialog = await this.ui.createDialog; + const docImport = await createDialog.documentImportLayout; + await docImport.fillMultipleValues(table); }); -Then('I click on Apply to all', function() { - this.ui.createDialog.applyAll.click(); +Then('I click on Apply to all', async function() { + const createDialog = await this.ui.createDialog; + const applyAll = await createDialog.applyAll; + await applyAll.click(); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/login.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/login.js index 12805216a1..e9cdeac68a 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/login.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/login.js @@ -1,10 +1,11 @@ -import { Given, Then, When } from '@cucumber/cucumber'; +import { Given, Then, When } from '../../node_modules/@cucumber/cucumber'; import Login from '../../pages/login'; import UI from '../../pages/ui'; import { url } from '../../pages/helpers'; -Given('user {string} exists in group {string}', (username, group) => - fixtures.users.create({ +Given('user {string} exists in group {string}', async (username, group) => { + const users = await fixtures.users; + await users.create({ 'entity-type': 'user', properties: { username, @@ -13,11 +14,12 @@ Given('user {string} exists in group {string}', (username, group) => password: fixtures.users.DEFAULT_PASSWORD, groups: [group], }, - }), -); + }); +}); -Given('user {string} exists', (username) => - fixtures.users.create({ +Given('user {string} exists', async (username) => { + const users = await fixtures.users; + await users.create({ 'entity-type': 'user', properties: { username, @@ -25,30 +27,35 @@ Given('user {string} exists', (username) => email: `${username}@test.com`, password: fixtures.users.DEFAULT_PASSWORD, }, - }), -); + }); +}); -When('I login as {string}', function(username) { - const login = Login.get(); - login.username = username; - login.password = users[username]; - login.submit(); +When('I login as {string}', async function(username) { + await driver.pause(2000); + const logIn = await Login.get(); + await logIn.username(username); + const password = await users[username]; + await logIn.password(password); + await logIn.submit(); this.username = username; - this.ui = UI.get(); - driver.waitForVisible('nuxeo-page'); + this.ui = await UI.get(); + await driver.pause(2000); + await this.ui.waitForVisible('nuxeo-page'); }); When(/^I visit (.*)$/, (path) => url(path)); -When('I logout', () => Login.get()); +When('I logout', async () => Login.get()); -Then('I am logged in as {string}', function(username) { - const currentUser = this.ui.drawer - .open('profile') - .element('.header') - .getText() - .toLowerCase(); - currentUser.should.be.equal(username.toLowerCase()); +Then('I am logged in as {string}', async function(username) { + const profileEle = await this.ui.drawer.open('profile'); + const headerEle = await profileEle.element('.header'); + await driver.pause(1000); + const currentUser = await headerEle.getText(); + currentUser.toLowerCase().should.be.equal(username.toLowerCase()); }); -Then('I am logged out', () => driver.isVisible('#username').should.be.true); +Then('I am logged out', async () => { + const isVisible = await driver.isVisible('#username'); + isVisible.should.be.true; +}); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/permissions.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/permissions.js index 1f5f22d6ba..cce3f94d76 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/permissions.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/permissions.js @@ -1,68 +1,93 @@ -import { Given, Then, When } from '@cucumber/cucumber'; +/* eslint-disable no-await-in-loop */ +import { Given, Then, When } from '../../node_modules/@cucumber/cucumber'; -When(/^I give (\w+) permission to "([^"]*)" on the document$/, function(permission, name) { - this.ui.browser.permissionsViewButton.waitForVisible(); - this.ui.browser.permissionsViewButton.click(); - this.ui.browser.permissionsView.waitForVisible(); - this.ui.browser.permissionsView.newPermissionButton.waitForVisible(); - this.ui.browser.permissionsView.newPermissionButton.click(); - this.ui.browser.permissionsView.setPermissions(name, { +When(/^I give (\w+) permission to "([^"]*)" on the document$/, async function(permission, name) { + const viewButtonEle = await this.ui.browser.permissionsViewButton; + await viewButtonEle.waitForVisible(); + await viewButtonEle.click(); + const viewEle = await this.ui.browser.permissionsView; + await viewEle.waitForVisible(); + const newPermissionEle = await viewEle.newPermissionButton; + await newPermissionEle.waitForVisible(); + await newPermissionEle.click(); + await viewEle.setPermissions(name, { permission, timeFrame: 'permanent', notify: false, }); - this.ui.browser.permissionsView.createPermissionButton.waitForVisible(); - this.ui.browser.permissionsView.createPermissionButton.click(); - this.ui.browser.permissionsView.permission(permission, name, 'permanent').waitForVisible(); + const createPermissionEle = await viewEle.createPermissionButton; + await createPermissionEle.waitForVisible(); + await createPermissionEle.click(); + const viewElement = await this.ui.browser.permissionsView; + await viewElement.permission(permission, name, 'permanent'); }); -When(/^I give (\w+) permission on the document to the following users:$/, function(permission, table) { - this.ui.browser.permissionsViewButton.waitForVisible(); - this.ui.browser.permissionsViewButton.click(); - this.ui.browser.permissionsView.waitForVisible(); - this.ui.browser.permissionsView.newPermissionButton.waitForVisible(); - this.ui.browser.permissionsView.newPermissionButton.click(); - - table.rows().forEach((row) => { - this.ui.browser.permissionsView.setPermissions(row[0], { +When(/^I give (\w+) permission on the document to the following users:$/, async function(permission, table) { + const viewButtonEle = await this.ui.browser.permissionsViewButton; + await viewButtonEle.waitForVisible(); + await viewButtonEle.click(); + const viewEle = await this.ui.browser.permissionsView; + await viewEle.waitForVisible(); + const newPermissionEle = await viewEle.newPermissionButton; + await newPermissionEle.waitForVisible(); + await newPermissionEle.click(); + const rows = table.rows(); + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + await viewEle.setPermissions(row[0], { permission, timeFrame: 'permanent', notify: false, }); - }); + } - this.ui.browser.permissionsView.createPermissionButton.waitForVisible(); - this.ui.browser.permissionsView.createPermissionButton.click(); + const createPermissionEle = await viewEle.createPermissionButton; + await createPermissionEle.waitForVisible(); + await createPermissionEle.click(); + await driver.pause(3000); }); -Given(/^"([^"]*)" has (\w+) permission on the document$/, function(name, permission) { - fixtures.documents.setPermissions(this.doc, permission, name).then((d) => { +Given(/^"([^"]*)" has (\w+) permission on the document$/, async function(name, permission) { + await fixtures.documents.setPermissions(this.doc, permission, name).then((d) => { this.doc = d; }); }); -Then(/^I can see that "([^"]*)" has the (\w+) permission$/, function(name, permission) { - this.ui.browser.permissionsView.permission(permission, name).waitForVisible().should.be.true; +Then(/^I can see that "([^"]*)" has the (\w+) permission$/, async function(name, permission) { + const permissionView = await this.ui.browser.permissionsView; + const permissionEle = await permissionView.permission(permission, name); + const isVisible = await permissionEle.waitForVisible(); + isVisible.should.be.true; }); -When(/^I edit the (\w+) permission on the document for "([^"]*)" to start (\w+)$/, function(permission, name, date) { - this.ui.browser.permissionsViewButton.waitForVisible(); - this.ui.browser.permissionsViewButton.click(); - this.ui.browser.permissionsView.waitForVisible(); - this.ui.browser.permissionsView.permission(permission, name).waitForVisible(); - this.ui.browser.permissionsView.editPermissionButton.waitForVisible(); +When(/^I edit the (\w+) permission on the document for "([^"]*)" to start (\w+)$/, async function( + permission, + name, + date, +) { + const viewButtonEle = this.ui.browser.permissionsViewButton; + await viewButtonEle.waitForVisible(); + await viewButtonEle.click(); + const viewEle = await this.ui.browser.permissionsView; + await viewEle.waitForVisible(); + const permissionEle = await viewEle.permission(permission, name); + await permissionEle.waitForVisible(); + const editPermissionEle = await viewEle.editPermissionButton; + await editPermissionEle.waitForVisible(); if (date === 'tomorrow') { date = new Date(); date.setDate(date.getDate() + 1); } - this.ui.browser.permissionsView.editPermissionButton.click(); - this.ui.browser.permissionsView.waitForVisible(); - this.ui.browser.permissionsView.editPermissions({ + await editPermissionEle.click(); + await viewEle.waitForVisible(); + await viewEle.editPermissions({ permission, timeFrame: 'datebased', begin: date, notify: false, }); - this.ui.browser.permissionsView.updatePermissionButton.click(); - this.ui.browser.permissionsView.permission(permission, name, 'datebased').waitForVisible(); + const updatePermission = await viewEle.updatePermissionButton; + await updatePermission.click(); + const permitEle = await viewEle.permission(permission, name, 'datebased'); + await permitEle.waitForVisible(); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/personal.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/personal.js index 236308e51d..c970b561b1 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/personal.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/personal.js @@ -1,5 +1,9 @@ -import { Then } from '@cucumber/cucumber'; +import { Then } from '../../node_modules/@cucumber/cucumber'; -Then('I can see my personal workspace', function() { - this.ui.drawer.personal.waitForVisible().should.be.true; +Then('I can see my personal workspace', async function() { + const personalEle = await this.ui.drawer.personal; + await personalEle.waitForVisible(); + if (!personalEle) { + throw new Error(`Expected my personal workspace not be visible`); + } }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/picture.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/picture.js index 4800900e5c..2d3e9a21c5 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/picture.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/picture.js @@ -1,7 +1,11 @@ -import { Then } from '@cucumber/cucumber'; +import { Then } from '../../node_modules/@cucumber/cucumber'; -Then('I can see the picture formats panel', function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.el.$('.additional').waitForVisible('nuxeo-picture-formats').should.be.true; +Then('I can see the picture formats panel', async function() { + const uiBrowser = await this.ui.browser; + const page = await uiBrowser.documentPage(this.doc.type); + await page.waitForVisible(); + const additionalPage = await page.el.element('.additional'); + await additionalPage.waitForVisible(); + const pageElement = await additionalPage.waitForVisible('nuxeo-picture-formats'); + await pageElement.should.be.true; }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/preview.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/preview.js index 2bf3f620e4..b29bf6a33e 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/preview.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/preview.js @@ -1,32 +1,37 @@ -import { Then, When } from '@cucumber/cucumber'; +import { Then, When } from '../../node_modules/@cucumber/cucumber'; -When('I click the preview button', function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.previewButton.waitForVisible(); - page.previewButton.click(); +When('I click the preview button', async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const buttonEle = await page.previewButton; + await buttonEle.waitForVisible(); + await buttonEle.click(); }); -When('I click the preview button for the attachment', function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.metadata.attachments.waitForVisible(); - page.metadata.attachments.previewButton.click(); +When('I click the preview button for the attachment', async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const attachEle = await page.metadata.attachments; + await attachEle.waitForVisible(); + const buttonEle = await attachEle.previewButton; + await buttonEle.click(); }); -Then(/^I can see the inline ([-\w]+) previewer$/, function(viewerType) { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.view.waitForVisible(); - const { preview } = page.view; - preview.waitForVisible(); +Then(/^I can see the inline ([-\w]+) previewer$/, async function(viewerType) { + const uiBrowser = await this.ui.browser; + const page = await uiBrowser.documentPage(this.doc.type); + await page.waitForVisible(); + const pageView = await page.view; + await pageView.waitForVisible(); + const preview = await pageView.preview; + await preview.waitForVisible(); if (viewerType === 'plain') { - preview.waitForVisible(`#${viewerType}`); + await preview.waitForVisible(`#${viewerType}`); return; } - preview.waitForVisible(viewerType); + await preview.waitForVisible(viewerType); }); -Then(/^I can see a ([-\w]+) previewer$/, (viewerType) => { - $(`#dialog ${viewerType}`).waitForVisible(); +Then(/^I can see a ([-\w]+) previewer$/, async (viewerType) => { + await $(`#dialog ${viewerType}`).waitForVisible(); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/recents.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/recents.js index fe329453d8..c49ede10ed 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/recents.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/recents.js @@ -1,21 +1,31 @@ -import { Then, When } from '@cucumber/cucumber'; +import { Then, When } from '../../node_modules/@cucumber/cucumber'; -When('I can click on recently viewed documents item {string}', function(title) { - this.ui.drawer.recents.waitForVisible(); - this.ui.drawer.recents.waitForHasMember(title).should.be.true; - this.ui.drawer.recents.select(title).should.be.true; +When('I can click on recently viewed documents item {string}', async function(title) { + await this.ui.drawer.recents.waitForVisible(); + const member = await this.ui.drawer.recents.waitForHasMember(title); + member.should.be.true; + const selectTitle = await this.ui.drawer.recents.select(title); + selectTitle.should.be.true; }); Then('I can see the list of recently viewed documents', function() { this.ui.drawer.recents.waitForVisible().should.be.true; }); -Then('I can see the list of recently viewed documents has {int} item(s)', function(nb) { - this.ui.drawer.recents.waitForVisible(); - driver.waitUntil(() => this.ui.drawer.recents.nbItems === nb); +Then('I can see the list of recently viewed documents has {int} item(s)', async function(nb) { + const drawer = await this.ui.drawer; + const recents = await drawer.recents; + await recents.waitForVisible(); + const item = await recents.nbItems; + if (item !== nb) { + throw Error(`Expected count of ${nb} but found ${item}`); + } }); -Then('I can see the list of recently viewed documents has {string} document', function(title) { - this.ui.drawer.recents.waitForVisible(); - this.ui.drawer.recents.waitForHasMember(title).should.be.true; +Then('I can see the list of recently viewed documents has {string} document', async function(title) { + const drawer = await this.ui.drawer; + const recents = await drawer.recents; + await recents.waitForVisible(); + const member = await recents.waitForHasMember(title); + member.should.be.true; }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/search.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/search.js index 5e3a7c0bd6..4b235ff587 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/search.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/search.js @@ -1,4 +1,4 @@ -import { Given, Then, When } from '@cucumber/cucumber'; +import { Given, Then, When } from '../../node_modules/@cucumber/cucumber'; import { url } from '../../pages/helpers'; Then('I can see the {string} search panel', function(name) { @@ -41,7 +41,7 @@ Given(/^I have the following users$/, (table) => ), ); -Given(/^I have the following documents$/, (table) => { +Given(/^I have the following documents$/, async (table) => { browser.pause(1000); const tasks = table.hashes().map((row) => () => { const { doctype, title, creator, nature, subjects, coverage, path, collections, tag, file } = row; @@ -111,114 +111,157 @@ When('I browse to the saved search', function() { url(`#!/doc/${this.savedSearch.id}`); }); -Then('I can see that my saved search "{word}" on "{word}" is selected', function(savedSearchName, searchName) { - this.ui.searchForm(searchName).menuButton.waitForVisible(); - const el = this.ui.searchForm(searchName).getSavedSearch(savedSearchName); - el.waitForExist().should.be.true; - el.getAttribute('class').should.equal('iron-selected'); +Then('I can see that my saved search "{word}" on "{word}" is selected', async function(savedSearchName, searchName) { + const searchForm = await this.ui.searchForm(searchName); + const menuButton = await searchForm.menuButton; + await menuButton.waitForVisible(); + const savedSearch = await this.ui.searchForm(searchName).getSavedSearch(savedSearchName); + const savedSearchExist = await savedSearch.waitForExist(); + savedSearchExist.should.be.true; + const attr = await savedSearch.getAttribute('class'); + attr.should.equal('iron-selected'); }); -When(/^I clear the (.+) search on (.+)$/, function(searchType, searchName) { - const searchForm = this.ui.searchForm(searchName); - searchForm.waitForVisible(); - searchForm.search(searchType); +When(/^I clear the (.+) search on (.+)$/, async function(searchType, searchName) { + const searchForm = await this.ui.searchForm(searchName); + await searchForm.waitForVisible(); + await searchForm.search(searchType); }); -When(/^I perform a (.+) search for (.+) on (.+)$/, function(searchType, searchTerm, searchName) { - const searchForm = this.ui.searchForm(searchName); - searchForm.waitForVisible(); - searchForm.search(searchType, searchTerm); +When(/^I perform a (.+) search for (.+) on (.+)$/, async function(searchType, searchTerm, searchName) { + const searchForm = await this.ui.searchForm(searchName); + await searchForm.waitForVisible(); + await driver.pause(3000); + await searchForm.search(searchType, searchTerm); }); -When('I switch to filter view', function() { - this.ui.filterView.click(); +When('I switch to filter view', async function() { + await driver.pause(3000); + const filterView = await this.ui.filterView; + await filterView.click(); + await browser.pause(3000); }); -Then(/^I can see (\d+) search results$/, function(numberOfResults) { - const { displayMode } = this.ui.results; +Then(/^I can see (\d+) search results$/, async function(numberOfResults) { + await driver.pause(2000); + const uiResult = await this.ui.results; + const displayMode = await uiResult.displayMode; if (numberOfResults === 0) { - driver.waitUntil( - () => this.ui.results.resultsCount(displayMode) === 0, - `Expecting to get ${numberOfResults} results but found ${this.ui.results.resultsCount(displayMode)}`, - ); - this.ui.results.noResults.waitForVisible().should.be.true; + const outResult2 = await uiResult.resultsCount(displayMode); + if (outResult2 !== numberOfResults) { + throw Error(`Expecting to get ${numberOfResults} results but found ${outResult2}`); + } + const emptyResult = await uiResult.noResults; + const emptyResultVisible = await emptyResult.waitForVisible(); + emptyResultVisible.should.be.true; } else { - this.ui.results.resultsCountLabel.waitForVisible(); - driver.waitUntil( - () => - parseInt(this.ui.results.resultsCountLabel.getText(), 10) === numberOfResults && - this.ui.results.resultsCount(displayMode) === numberOfResults, - `Expecting to get ${numberOfResults} results but found ${this.ui.results.resultsCount(displayMode)}`, - ); + const outLabel = await uiResult.resultsCountLabel; + await outLabel.waitForVisible(); + const outText = await outLabel.getText(); + const outResult = parseInt(outText, 10); + if (outResult !== numberOfResults) { + throw Error(`Expecting to get ${numberOfResults} results but found ${outResult}`); + } + const outResult2 = await uiResult.resultsCount(displayMode); + if (outResult2 !== numberOfResults) { + throw Error(`Expecting to get ${numberOfResults} results but found ${outResult2}`); + } } }); -Then(/^I can see more than (\d+) search results$/, function(minNumberOfResults) { - const { displayMode } = this.ui.results; - driver.waitUntil( - () => this.ui.results.resultsCount(displayMode) > minNumberOfResults, - `Expecting to get more than ${minNumberOfResults} results but found ${this.ui.results.resultsCount(displayMode)}`, - ); +Then(/^I can see more than (\d+) search results$/, async function(minNumberOfResults) { + await driver.pause(3000); + const results = await this.ui.results; + const displayMode = await results.displayMode; + const output = await results.resultsCount(displayMode); + if (output > minNumberOfResults) { + return true; + } + throw Error(`Expecting to get more than ${minNumberOfResults} but found ${output}`); }); -Then('I edit the results columns to show {string}', function(heading) { - this.ui.results.actions.waitForVisible(); - if (this.ui.results.displayMode !== 'table' && this.ui.results.toggleTableView.isVisible()) { - this.ui.results.toggleTableView.click(); +Then('I edit the results columns to show {string}', async function(heading) { + const result = await this.ui.results; + const actions = await result.actions; + await actions.waitForVisible(); + const dispMode = await result.displayMode; + const togTableview = await result.toggleTableView; + if ((await dispMode) !== 'table' && (await togTableview.isVisible())) { + await togTableview.click(); } - this.ui.results.toggleColumnSettings.waitForVisible(); - this.ui.results.toggleColumnSettings.click(); - this.ui.results.getColumnCheckbox(heading).waitForExist(); - this.ui.results.checkColumnCheckbox(heading); - this.ui.results.columnsCloseButton.click(); - this.ui.results.getResultsColumn(heading).waitForExist().should.be.true; -}); - -Then(/^I save my search as "(.+)"$/, function(searchName) { - this.ui.searchResults.saveSearchAsButton.waitForVisible(); - this.ui.searchResults.saveSearchAsButton.click(); - this.ui.searchResults.enterInput(searchName); - this.ui.searchResults.confirmSaveSearchButton.click(); -}); - -Then(/^I share my "(.+)" search with (.+)/, function(searchName, username) { - this.ui.searchResults.savedSearchActionButton.waitForVisible(); - this.ui.searchResults.savedSearchActionButton.click(); - this.ui.searchResults.shareAction.waitForVisible(); - this.ui.searchResults.shareAction.click(); - this.ui.searchForm(searchName).permissionsView.newPermissionButton.waitForVisible(); - this.ui.searchForm(searchName).permissionsView.newPermissionButton.click(); - this.ui.searchForm(searchName).permissionsView.setPermissions(username, { + const toggleSettings = await result.toggleColumnSettings; + await toggleSettings.waitForVisible(); + await toggleSettings.click(); + const columnCheckbox = await result.getColumnCheckbox(heading); + await columnCheckbox.waitForExist(); + await result.checkColumnCheckbox(heading); + const button = await result.columnsCloseButton; + await button.click(); + const resultsColumn = await result.getResultsColumn(heading); + const isColumnExist = await resultsColumn.waitForExist(); + isColumnExist.should.be.true; +}); + +Then(/^I save my search as "(.+)"$/, async function(searchName) { + const saveAsButton = await this.ui.searchResults.saveSearchAsButton; + await saveAsButton.waitForVisible(); + await saveAsButton.click(); + await this.ui.searchResults.enterInput(searchName); + const confirmSaveButton = await this.ui.searchResults.confirmSaveSearchButton; + await confirmSaveButton.click(); +}); + +Then(/^I share my "(.+)" search with (.+)/, async function(searchName, username) { + const savedSearchButton = await this.ui.searchResults.savedSearchActionButton; + await savedSearchButton.waitForVisible(); + await savedSearchButton.click(); + const shareActionButton = await this.ui.searchResults.shareAction; + await shareActionButton.waitForVisible(); + await shareActionButton.click(); + const searchForm = await this.ui.searchForm(searchName); + const PremissionButton = await searchForm.permissionsView.newPermissionButton; + await PremissionButton.waitForVisible(); + await PremissionButton.click(); + await searchForm.permissionsView.setPermissions(username, { permission: 'Read', timeFrame: 'permanent', notify: false, }); - this.ui.searchForm(searchName).permissionsView.createPermissionButton.waitForVisible(); - this.ui.searchForm(searchName).permissionsView.createPermissionButton.click(); - this.ui - .searchForm(searchName) - .permissionsView.permission('Read', username, 'permanent') - .waitForVisible(); + const createPermissionButton = await searchForm.permissionsView.createPermissionButton; + await createPermissionButton.waitForVisible(); + await createPermissionButton.click(); + const permissionView = await searchForm.permissionsView; + const permissionVisible = await permissionView.permission('Read', username, 'permanent'); + const isVisible = await permissionVisible.waitForVisible(); + isVisible.should.be.true; }); -Then(/^I can view my saved search "(.+)" on "(.+)"$/, function(savedSearchName, searchName) { - this.ui.searchForm(searchName).menuButton.waitForVisible(); - this.ui.searchForm(searchName).menuButton.click(); - this.ui - .searchForm(searchName) - .getSavedSearch(savedSearchName) - .waitForExist().should.be.true; +Then(/^I can view my saved search "(.+)" on "(.+)"$/, async function(savedSearchName, searchName) { + const searchForm = await this.ui.searchForm(searchName); + const menuButton = await searchForm.menuButton; + await menuButton.waitForVisible(); + await menuButton.click(); + const savedSearch = await searchForm.getSavedSearch(savedSearchName); + const savedSearchExist = await savedSearch.waitForExist(); + savedSearchExist.should.be.true; }); -When(/^I click the QuickSearch button$/, function() { - this.ui.searchButton.waitForVisible(); - this.ui.searchButton.click(); +When(/^I click the QuickSearch button$/, async function() { + const button = await this.ui.searchButton; + await button.waitForVisible(); + await button.click(); }); -When(/^I perform a QuickSearch for (.+)/, function(searchTerm) { - return this.ui.quickSearch.enterInput(searchTerm); +When(/^I perform a QuickSearch for (.+)/, async function(searchTerm) { + const quickSearch = await this.ui.quickSearch; + await quickSearch.enterInput(searchTerm); }); -Then(/^I can see (\d+) QuickSearch results$/, function(numberOfResults) { - driver.waitUntil(() => this.ui.quickSearch.quickSearchResultsCount() === numberOfResults); +Then(/^I can see (\d+) QuickSearch results$/, async function(numberOfResults) { + const quickSearch = await this.ui.quickSearch; + await driver.pause(1000); + const result = await quickSearch.quickSearchResultsCount(); + if (result !== numberOfResults) { + throw Error(`Expecting to get ${numberOfResults} results but found ${result}`); + } }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/spreadsheet.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/spreadsheet.js new file mode 100644 index 0000000000..a211fe6ef8 --- /dev/null +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/spreadsheet.js @@ -0,0 +1,84 @@ +import { Then, When } from '../../node_modules/@cucumber/cucumber'; +import Spreadsheet from '../../pages/spreadsheet'; + +When('I open the spreadsheet', async function() { + const result = await this.ui.results; + const browser = await this.ui.browser; + const actions = await result.actions; + const buttonEle = await actions.element('nuxeo-spreadsheet-button'); + await buttonEle.click(); + const dialog = await buttonEle.element('#dialog'); + await dialog.waitForVisible(); + const iframe = await buttonEle.element('#iframe'); + await iframe.waitForExist(); + const browserEle = await browser.el; + await browserEle.switchToFrame(iframe); + this.spreadsheet = await new Spreadsheet(); +}); + +When('I see the spreadsheet dialog', function() { + const button = this.ui.browser.results.actions.element('nuxeo-spreadsheet-button'); + button.waitForVisible('#dialog'); +}); + +Then('I can see the spreadsheet results actions button', async function() { + const currentUI = await this.ui; + const results = await currentUI.results; + if ((await results.displayMode) !== 'table') { + const toggleTableViewBtn = await results.toggleTableView; + await toggleTableViewBtn.click(); + } + const button = await results.actions; + await button.waitForVisible('nuxeo-spreadsheet-button'); +}); + +Then('I can see the {string} spreadsheet column', async function(column) { + const spreadsheet = await this.spreadsheet; + if (spreadsheet) { + const header = await spreadsheet.headers; + await header.includes(column); + } else { + throw Error('Error: Spreadsheet does not exist!!'); + } +}); + +When('I set the spreadsheet cell {int},{int} to {string}', async function(row, col, value) { + const spreadsheet = await this.spreadsheet; + if (spreadsheet) { + spreadsheet.setData(row, col, value); + } else { + throw Error('Error: Spreadsheet does not exist!!'); + } +}); + +When('I save the spreadsheet', async function() { + const spreadsheet = await this.spreadsheet; + if (spreadsheet) { + await spreadsheet.save(); + const consoleEle = await spreadsheet.console; + await consoleEle.getText(); + } else { + throw Error('Error: Spreadsheet does not exist!!'); + } +}); + +When('I close the spreadsheet', async function() { + const spreadsheet = await this.spreadsheet; + if (spreadsheet) { + await spreadsheet.close(); + await browser.switchToFrame(null); + } else { + throw Error('Error: Spreadsheet does not exist!!'); + } +}); + +Then('I see {string} in the results table cell {int},{int}', async function(value, row, col) { + const results = await this.ui.results; + await results.waitForVisible(); + const tableRow = await results.el.elements('nuxeo-data-table-row:not([header])'); + const tableRowValue = await tableRow[row]; + const tableCell = await tableRowValue.elements('nuxeo-data-table-cell'); + const tableCol = await tableCell[col]; + const tableColText = await tableCol.getText(); + tableColText.should.be.equal(value); +}); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/_fixtures.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/_fixtures.js index efbbb0f807..32eb7c4a6a 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/_fixtures.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/_fixtures.js @@ -1 +1 @@ -global.fixtures = {}; +// global.fixtures = {}; diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/comments.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/comments.js index 9c981dd8a3..1e4d134a26 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/comments.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/comments.js @@ -1,5 +1,5 @@ -import { After } from '@cucumber/cucumber'; import Nuxeo from 'nuxeo'; +import { After } from '../../../../node_modules/@cucumber/cucumber'; global.addedComments = []; diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/consumers.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/consumers.js index 9e4c1fd9c4..3f84212299 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/consumers.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/consumers.js @@ -1,4 +1,4 @@ -import { After } from '@cucumber/cucumber'; +import { After } from '../../../../node_modules/@cucumber/cucumber'; import nuxeo from '../services/client'; const endPoint = '/oauth2/client/'; diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/documents.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/documents.js index 78bad788ee..80e53cc37b 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/documents.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/documents.js @@ -1,4 +1,4 @@ -import { After, Before } from '@cucumber/cucumber'; +import { After, Before } from '../../../../node_modules/@cucumber/cucumber'; import documentService from '../services/documentService'; fixtures.documents = documentService; diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/groups.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/groups.js index 8394c6445a..7753a1c0ab 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/groups.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/groups.js @@ -1,4 +1,4 @@ -import { After } from '@cucumber/cucumber'; +import { After } from '../../../../node_modules/@cucumber/cucumber'; import nuxeo from '../services/client'; global.groups = { diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/layouts.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/layouts.js index 0d94e4068a..828e47fcb6 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/layouts.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/layouts.js @@ -1,95 +1,115 @@ +/* eslint-disable no-await-in-loop */ import path from 'path'; import FieldRegistry from '../services/field_registry'; global.fieldRegistry = new FieldRegistry(); -const suggestionGet = (element) => { - if (element.getAttribute('multiple') !== null) { - return element - .elements('.selectivity-multiple-selected-item') - .map((v) => v.getText()) - .join(','); +const suggestionGet = async (element) => { + const multiElement = await element.getAttribute('multiple'); + const isMulti = multiElement !== null; + if (isMulti) { + const multiSelectivity = await element.elements('.selectivity-multiple-selected-item'); + const filedValues = []; + for (let index = 0; index < multiSelectivity.length; index++) { + const singleText = await multiSelectivity[index].getText(); + filedValues.push(singleText); + } + return filedValues.join(','); } - return element.element('.selectivity-single-selected-item').getText(); + const singleElement = await element.element('.selectivity-single-selected-item'); + const singleElementText = await singleElement.getText(); + return singleElementText; }; -const suggestionSet = (element, value) => { - const isMulti = element.getAttribute('multiple') !== null; +const suggestionSet = async (element, value) => { + const multiElement = await element.getAttribute('multiple'); + const isMulti = multiElement !== null; if (value) { const values = isMulti ? value.split(',') : [value]; - element.waitForExist('#input'); - element.scrollIntoView('#input'); + await element.waitForExist('#input'); + await element.scrollIntoView('#input'); + for (let i = 0; i < values.length; i++) { element.waitForVisible(isMulti ? 'input' : '#input'); - element.element(isMulti ? 'input' : '.selectivity-caret').click(); - let dropdown = element.element('.selectivity-dropdown:last-child'); + const currentElement = await element.element(isMulti ? 'input' : '.selectivity-caret'); + await currentElement.click(); + let dropdown = await element.element('.selectivity-dropdown:last-child'); if (isMulti) { element.waitForVisible('.selectivity-multiple-input'); - element.element('.selectivity-multiple-input').setValue(values[i]); + const multipleInput = await element.element('.selectivity-multiple-input'); + await multipleInput.setValue(values[i]); } else { - const hasSelectedValue = element.element('.selectivity-single-selected-item').isExisting(); - dropdown.waitForVisible('.selectivity-search-input'); - dropdown.element('.selectivity-search-input').setValue(values[i]); + const singleSelectivity = await element.element('.selectivity-single-selected-item'); + const hasSelectedValue = await singleSelectivity.isExisting(); + await dropdown.waitForVisible('.selectivity-search-input'); + const searchInput = await dropdown.element('.selectivity-search-input'); + await searchInput.setValue(values[i]); if (hasSelectedValue) { - dropdown.element('.selectivity-result-item').waitForVisible(); - driver.keys('Down arrow'); + const dropdownElement = await dropdown.element('.selectivity-result-item'); + await dropdownElement.waitForVisible(); + await driver.keys('Down arrow'); } } - driver.waitUntil(() => { - try { - dropdown = element.element('.selectivity-dropdown:last-child'); - if (dropdown.isVisible('.selectivity-result-item.highlight')) { - const highlight = dropdown.element('.selectivity-result-item.highlight'); - if ( - highlight - .getText() - .trim() - .includes(values[i]) - ) { - dropdown.click('.selectivity-result-item.highlight'); - return true; - } - return false; + try { + dropdown = await element.element('.selectivity-dropdown:last-child'); + const dropdownHighlight = await dropdown.$('.selectivity-result-item.highlight'); + if (await dropdownHighlight.isVisible()) { + const highLightText = await dropdownHighlight.getText(); + const hightlightTrimText = highLightText.trim(); + if (hightlightTrimText.includes(values[i])) { + await dropdownHighlight.click(); + return true; } return false; - } catch (e) { - return false; } - }); + return false; + } catch (e) { + return false; + } + } + } + // it's a reset + else if (multiElement !== null) { + const dropdown = await element.elements('.selectivity-multiple-selected-item'); + for (let i = 0; i < dropdown.length; i++) { + const dropdownElement = await dropdown[i].element('.selectivity-multiple-selected-item-remove'); + await dropdownElement.click(); } - // it's a reset - } else if (element.getAttribute('multiple') !== null) { - element - .elements('.selectivity-multiple-selected-item') - .forEach((el) => el.element('.selectivity-multiple-selected-item-remove').click()); } else { - const item = element.element('.selectivity-single-selected-item'); + const item = await element.element('.selectivity-single-selected-item'); if (item) { - item.element('.selectivity-single-selected-item-remove').click(); + const ele = await item.element('.selectivity-single-selected-item-remove'); + await ele.click(); } } }; global.fieldRegistry.register( 'nuxeo-input', - (element) => element.element('.input-element input').getValue(), - (element, value) => { - element.element('.input-element input').setValue(value); + async (element) => element.$('.input-element input').getValue(), + async (element, value) => { + const ele = await element.$('.input-element input'); + await ele.setValue(value); }, ); global.fieldRegistry.register( 'nuxeo-select', (element) => { - element.element('.input-element input').getValue(); + element.$('.input-element input').getValue(); }, - (element, value) => { - element.element('.input-element input').click(); - element.waitForExist('paper-item'); - const item = element.elements('paper-item').find((e) => e.getText() === value); - item.click(); + async (element, value) => { + const input = await element.$('.input-element input'); + await input.click(); + await element.$('paper-item').waitForExist(); + const rows = await element.$$('paper-item'); + const elementTitle = await element.$$('paper-item').map((img) => img.getText()); + const index = elementTitle.findIndex((currenTitle) => currenTitle === value); + const item = await rows[index]; + await item.click(); }, ); global.fieldRegistry.register( 'nuxeo-date', - (element) => { - const date = moment(element.element('#datetime').getText(), global.dateFormat).format(global.dateFormat); + async (element) => { + const dateEle = await element.element('#datetime'); + const date = moment(dateEle.getText(), global.dateFormat).format(global.dateFormat); return date; }, () => { @@ -98,24 +118,25 @@ global.fieldRegistry.register( ); global.fieldRegistry.register( 'nuxeo-date-picker', - (element) => - moment(element.element('vaadin-date-picker input').getValue(), global.dateFormat).format(global.dateFormat), - (element, value) => { - const date = element.element('vaadin-date-picker input'); - if (date.getValue()) { - date.element('div[part="clear-button"]').click(); + (element) => moment(element.$('vaadin-date-picker input').getValue(), global.dateFormat).format(global.dateFormat), + async (element, value) => { + const date = await element.$('vaadin-date-picker input'); + if (await date.getValue()) { + const ele = await date.$('div[part="clear-button"]'); + await ele.click(); } - date.click(); - const keys = moment(value, global.dateFormat).format('L'); - driver.keys(keys); - driver.keys('Enter'); + await date.click(); + const keys = await moment(value, global.dateFormat).format('L'); + await driver.keys(keys); + await driver.keys('Enter'); }, ); global.fieldRegistry.register( 'nuxeo-textarea', (element) => element.element('#textarea').getValue(), - (element, value) => { - element.element('#textarea').setValue(value); + async (element, value) => { + const ele = await element.$('#textarea'); + await ele.setValue(value); }, ); global.fieldRegistry.register('nuxeo-user-suggestion', suggestionGet, suggestionSet); @@ -125,48 +146,50 @@ global.fieldRegistry.register('nuxeo-dropdown-aggregation', suggestionGet, sugge global.fieldRegistry.register('nuxeo-selectivity', suggestionGet, suggestionSet); global.fieldRegistry.register( 'nuxeo-select2', - (element) => element.element('div ul li input').getValue(), + (element) => element.$('div ul li input').getValue(), (element, value) => { - element.element('div ul li input').click(); - driver.element('div ul li input').setValue(value); + element.$('div ul li input').click(); + driver.$('div ul li input').setValue(value); $(`//div[text()='${value}' and @class='select2-result-label']`).waitForVisible(); - driver.element(`//div[text()='${value}' and @class='select2-result-label']`).click(); + driver.$(`//div[text()='${value}' and @class='select2-result-label']`).click(); }, ); global.fieldRegistry.register('nuxeo-tag-suggestion', suggestionGet, suggestionSet); global.fieldRegistry.register( 'paper-input', - (element) => element.element('.input-element input').getValue(), + (element) => element.$('.input-element input').getValue(), (element, value) => { - element.element('.input-element input').setValue(value); + element.$('.input-element input').setValue(value); }, ); global.fieldRegistry.register( 'paper-radio-button', - (element) => element.element('#radioContainer').getAttribute('multiple') !== null, - (element, value) => { + (element) => element.$('#radioContainer').getAttribute('multiple') !== null, + async (element, value) => { if (value) { - element.element('#radioContainer').click(); + const setEle = await element.element('#radioContainer'); + await setEle.click(); } }, ); global.fieldRegistry.register( 'paper-textarea', - (element) => element.element('#textarea').getValue(), + (element) => element.$('#textarea').getValue(), (element, value) => { - element.element('#textarea').setValue(value); + element.$('#textarea').setValue(value); }, ); global.fieldRegistry.register( 'paper-checkbox', (element) => element.getAttribute('checked') !== null, - (element, value) => { + async (element, value) => { + const ele = await element.getAttribute('checked'); if ( - ((value === false || value === 'false') && element.getAttribute('checked') !== null) || - ((value === true || value === 'true') && element.getAttribute('checked') === null) + ((value === false || value === 'false') && ele !== null) || + ((value === true || value === 'true') && ele === null) ) { - element.scrollIntoView(); - element.click(); + await element.scrollIntoView(); + await element.click(); } }, ); @@ -175,33 +198,34 @@ global.fieldRegistry.register( (element) => { let el = element; if (el.getAttribute('collapsible') !== null) { - el = el.element('iron-collapse'); + el = el.$('iron-collapse'); } - return el.element('paper-checkbox').getAttribute('aria-checked') !== null; + return el.$('paper-checkbox').getAttribute('aria-checked') !== null; }, - (element, value) => { + async (element, value) => { let el = element; - el.waitForVisible(); - if (el.getAttribute('collapsible') !== null) { - el = el.element('iron-collapse'); - const button = element.element('button'); - button.waitForVisible(); - button.click(); + await el.waitForVisible(); + if ((await el.getAttribute('collapsible')) !== null) { + el = await el.element('iron-collapse'); + const button = await element.$('button'); + await button.waitForVisible(); + await button.click(); } - el.waitForVisible('paper-checkbox'); - const els = el.elements('paper-checkbox'); - const checkbox = els.find((e) => { - const text = e.getText(); + const paperCheckbox = await el.$('paper-checkbox'); + await paperCheckbox.waitForVisible(); + const els = await el.$$('paper-checkbox'); + const checkbox = await els.find(async (e) => { + const text = await e.getText(); return typeof text === 'string' && text.trim().includes(value); }); - checkbox.click(); + await checkbox.click(); }, ); global.fieldRegistry.register( 'nuxeo-dropzone', - (element) => element.element("input[id='input']").getValue(), - (element, value) => { - element.waitForExist("input[id='input']"); + async (element) => element.$("input[id='input']").getValue(), + async (element, value) => { + await element.waitForExist("input[id='input']"); element.chooseFile("input[id='input']", path.resolve(fixtures.blobs.get(value))); }, ); @@ -210,9 +234,9 @@ global.fieldRegistry.register( (element) => { element.scrollIntoView(); const result = []; - element.elements('nuxeo-data-table-row:not([header])').forEach((row) => { + element.$$('nuxeo-data-table-row:not([header])').forEach((row) => { const cellValue = []; - row.elements('nuxeo-data-table-cell:not([header])').forEach((cell) => { + row.$$('nuxeo-data-table-cell:not([header])').forEach((cell) => { const txt = cell.getText(); if (txt) { cellValue.push(txt); @@ -222,44 +246,51 @@ global.fieldRegistry.register( }); return JSON.stringify(result); }, - (element, values) => { - element.scrollIntoView(); + async (element, values) => { + await element.scrollIntoView(); const jValues = JSON.parse(values); - jValues.forEach((value) => { - element.element('#addEntry').click(); - const dialog = element.element('nuxeo-dialog[id="dialog"]:not([aria-hidden])'); - dialog.waitForVisible(); - const form = element.element('#editForm'); - form.waitForVisible(); - Object.keys(value).forEach((property) => { - form.waitForVisible(`[name="${property}"]`); - fixtures.layouts.setValue(form.element(`[name="${property}"]`), value[property]); - }); - dialog.waitForVisible('paper-button[id="save"]'); - dialog.click('paper-button[id="save"]'); - }); + for (let index = 0; index < jValues.length; index++) { + const value = jValues[index]; + const addEntryEle = await element.element('#addEntry'); + await addEntryEle.click(); + const dialog = await element.element('nuxeo-dialog[id="dialog"]:not([aria-hidden])'); + await dialog.waitForVisible(); + const form = await element.element('#editForm'); + await form.waitForVisible(); + const objKeys = Object.keys(value); + for (let ind = 0; ind < objKeys.length; ind++) { + const property = objKeys[ind]; + await form.waitForVisible(`[name="${property}"]`); + const formEle = await form.element(`[name="${property}"]`); + await fixtures.layouts.setValue(formEle, value[property]); + } + await dialog.waitForVisible('paper-button[id="save"]'); + await dialog.$('paper-button[id="save"]').click(); + } }, ); global.fieldRegistry.register('nuxeo-document-blob', (element) => { element.scrollIntoView(); - return element.element('a').getAttribute('title'); + return element.$('a').getAttribute('title'); }); global.fieldRegistry.register( 'generic', (element) => element.getText(), - (element, value) => element.setValue(value), + async (element, value) => { + await element.setValue(value); + }, ); fixtures.layouts = { - getValue: (element) => { - const fieldType = element.getTagName(); + getValue: async (element) => { + const fieldType = await element.getTagName(); return (global.fieldRegistry.contains(fieldType) - ? global.fieldRegistry.getValFunc(fieldType) + ? await global.fieldRegistry.getValFunc(fieldType) : global.fieldRegistry.getValFunc('generic'))(element); }, - setValue: (element, value) => { - const fieldType = element.getTagName(); - (global.fieldRegistry.contains(fieldType) + setValue: async (element, value) => { + const fieldType = await element.getTagName(); + await (global.fieldRegistry.contains(fieldType) ? global.fieldRegistry.setValFunc(fieldType) : global.fieldRegistry.setValFunc('generic'))(element, value); }, diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/localstorage.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/localstorage.js index 222c85c6a2..15ba958f3c 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/localstorage.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/localstorage.js @@ -1,4 +1,4 @@ -import { After } from '@cucumber/cucumber'; +import { After } from '../../../../node_modules/@cucumber/cucumber'; /* global document, localStorage */ // cleans up local storage fo the current user diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/oauth2.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/oauth2.js index d872b6e046..8c44cf744a 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/oauth2.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/oauth2.js @@ -1,7 +1,7 @@ /** * Provisioning of OAuth2 providers, clients and tokens via oauth2/directory rest endpoint */ -import { After } from '@cucumber/cucumber'; +import { After } from '../../../../node_modules/@cucumber/cucumber'; import nuxeo from '../services/client'; import '../services/date'; @@ -68,14 +68,18 @@ fixtures.oauth2Clients = { delete: (entryId) => oauth2ClientsDir.delete(entryId).then(() => delete global.oauth2Clients[entryId]), }; -After(() => +After(async () => Promise.all([ Promise.all( - Object.keys(global.oauth2Providers).map((provider) => fixtures.oauth2Providers.delete(provider).catch(() => {})), + Object.keys(global.oauth2Providers).map(async (provider) => + fixtures.oauth2Providers.delete(provider).catch(() => {}), + ), ), Promise.all( - Object.keys(global.oauth2Clients).map((client) => fixtures.oauth2Clients.delete(client).catch(() => {})), + Object.keys(global.oauth2Clients).map(async (client) => fixtures.oauth2Clients.delete(client).catch(() => {})), + ), + Promise.all( + Object.keys(global.oauth2Tokens).map(async (token) => fixtures.oauth2Tokens.delete(token).catch(() => {})), ), - Promise.all(Object.keys(global.oauth2Tokens).map((token) => fixtures.oauth2Tokens.delete(token).catch(() => {}))), ]), ); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/providers.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/providers.js index 9a99561dac..dcd5bafc22 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/providers.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/providers.js @@ -1,4 +1,4 @@ -import { After } from '@cucumber/cucumber'; +import { After } from '../../../../node_modules/@cucumber/cucumber'; import nuxeo from '../services/client'; const endPoint = '/oauth2/provider/'; @@ -43,4 +43,6 @@ fixtures.providers = { .then(() => delete global.providers[provider]), }; -After(() => Promise.all(Object.keys(global.providers).map((provider) => fixtures.providers.delete(provider)))); +After(async () => + Promise.all(Object.keys(global.providers).map(async (provider) => fixtures.providers.delete(provider))), +); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/searches.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/searches.js index 6c6b2a4dac..d5eeb10ba3 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/searches.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/searches.js @@ -1,4 +1,4 @@ -import { After } from '@cucumber/cucumber'; +import { After } from '../../../../node_modules/@cucumber/cucumber'; import nuxeo from '../services/client'; fixtures.savedSearches = { diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/users.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/users.js index 0f3c9652dd..4618eae95c 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/users.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/users.js @@ -1,4 +1,4 @@ -import { After } from '@cucumber/cucumber'; +import { After } from '../../../../node_modules/@cucumber/cucumber'; import nuxeo from '../services/client'; global.users = { diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/vocabularies.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/vocabularies.js index 92e8f3f9e1..3d4914d2d6 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/vocabularies.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/vocabularies.js @@ -1,4 +1,4 @@ -import { After } from '@cucumber/cucumber'; +import { After } from '../../../../node_modules/@cucumber/cucumber'; import nuxeo from '../services/client'; global.addedVocabularyEntries = []; diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/workflows.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/workflows.js index e41b011585..48fd80bedf 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/workflows.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/fixtures/workflows.js @@ -1,11 +1,11 @@ -import { After } from '@cucumber/cucumber'; import Nuxeo from 'nuxeo'; +import { After } from '../../../../node_modules/@cucumber/cucumber'; import nuxeo from '../services/client'; global.runningWorkflows = []; - +global.fixtures = {}; fixtures.workflows = { - start: (document, workflowModelName, initiator) => { + start: async (document, workflowModelName, initiator) => { // creating a different client to make sure the initiator of the workflow is the logged-in user const client = new Nuxeo({ auth: { @@ -21,16 +21,14 @@ fixtures.workflows = { attachedDocumentIds: [document.uid], }; - return client - .workflows() - .start(workflowModelName, workflowOptions) - .then((workflowInstance) => { - runningWorkflows.push(workflowInstance.id); - return workflowInstance; - }); + const workflow = await client.workflows().start(workflowModelName, workflowOptions); + await runningWorkflows.push(workflow.id); + return workflow; }, - delete: (workflowInstanceId) => nuxeo.workflows().delete(workflowInstanceId), + delete: (workflowInstanceId) => { + nuxeo.workflows().delete(workflowInstanceId); + }, removeInstance: (workflowInstanceId) => { const index = runningWorkflows.indexOf(workflowInstanceId); @@ -44,9 +42,7 @@ After(() => Promise.all( Object.keys(runningWorkflows).map((index) => { const workflowInstanceId = runningWorkflows[index]; - return fixtures.workflows - .delete(workflowInstanceId) - .then(() => fixtures.workflows.removeInstance(workflowInstanceId)); + return fixtures.workflows.removeInstance(workflowInstanceId); }), ), ); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/screenshots.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/screenshots.js index a62901ec65..ced0ad9c3d 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/screenshots.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/screenshots.js @@ -1,13 +1,13 @@ import * as path from 'path'; import * as mkdirp from 'mkdirp'; -import { After, Status } from '@cucumber/cucumber'; +import { After, Status } from '../../../node_modules/@cucumber/cucumber'; -After(function(scenario) { +After(async function(scenario) { const { status } = scenario.result; if (process.env.SCREENSHOTS_PATH && status === Status.FAILED) { mkdirp.sync(process.env.SCREENSHOTS_PATH); const filename = path.join(process.env.SCREENSHOTS_PATH, `${scenario.pickle.name} (${status}).png`); - const screenshot = browser.saveScreenshot(filename); + const screenshot = await browser.saveScreenshot(filename); this.attach(screenshot, 'image/png'); } }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/ui_config.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/ui_config.js index 175fe2816e..5e20d2144d 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/support/ui_config.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/support/ui_config.js @@ -1,4 +1,4 @@ -import { Before } from '@cucumber/cucumber'; +import { Before } from '../../../node_modules/@cucumber/cucumber'; Before((e) => { const { tags } = e.pickle; diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/tasks.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/tasks.js index 8a1d1ec4b2..981e4cc50a 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/tasks.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/tasks.js @@ -1,68 +1,96 @@ -import { Then, When } from '@cucumber/cucumber'; +import { Then, When } from '../../node_modules/@cucumber/cucumber'; -When('I click the View Tasks Dashboard link', function() { - this.ui.drawer.tasks.dashboardLink.click(); +When('I click the View Tasks Dashboard link', async function() { + const dashboardLink = await this.ui.drawer.tasks.dashboardLink; + await dashboardLink.click(); }); -When(/^I (\w+) the task for following actors:$/, function(option, table) { +When(/^I (\w+) the task for following actors:$/, async function(option, table) { option.should.to.be.oneOf(['delegate', 'reassign'], 'An unknown type was passed as argument'); if (option === 'delegate') { - this.ui.browser.documentTaskView.delegateOption.click(); + const delegateOption = await this.ui.browser.documentTaskView.delegateOption; + await delegateOption.isVisible(); + await delegateOption.click(); } else if (option === 'reassign') { - this.ui.browser.documentTaskView.reassignOption.click(); + const reassignOption = await this.ui.browser.documentTaskView.reassignOption; + await reassignOption.isVisible(); + await reassignOption.click(); } - table.rows().map((row) => this.ui.browser.documentTaskView.setUserOrGroup(row[0])); - - this.ui.browser.documentTaskView.confirmButton.waitForVisible(); - this.ui.browser.documentTaskView.confirmButton.click(); - driver.waitForExist('iron-overlay-backdrop', driver.options.waitForTimeout, true); + const rows = table.rows(); + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + // eslint-disable-next-line no-await-in-loop + await this.ui.browser.documentTaskView.setUserOrGroup(row[0]); + } + const confirmButton = await this.ui.browser.documentTaskView.confirmButton; + await confirmButton.waitForVisible(); + await confirmButton.click(); + await driver.waitForExist('iron-overlay-backdrop', 5000, true); }); -Then('I can see the list of tasks', function() { - this.ui.drawer.tasks.waitForVisible().should.be.true; +Then('I can see the list of tasks', async function() { + const task = await this.ui.drawer.tasks.waitForVisible(); + task.should.be.true; }); -Then('I can see the View Tasks Dashboard link', function() { - this.ui.drawer.tasks.dashboardLink.waitForVisible().should.be.true; +Then('I can see the View Tasks Dashboard link', async function() { + const dashboardLink = await this.ui.drawer.tasks.dashboardLink; + const output = await dashboardLink.waitForVisible(); + output.should.be.true; }); -Then('I can see the Tasks Dashboard', function() { - this.ui.tasks.waitForVisible().should.be.true; +Then('I can see the Tasks Dashboard', async function() { + const taskVisible = await this.ui.tasks.waitForVisible(); + taskVisible.should.be.true; }); -Then(/^I can process the workflow$/, function() { - this.ui.browser.documentTaskView.waitForVisible(); +Then(/^I can process the workflow$/, async function() { + await this.ui.browser.documentTaskView.waitForVisible(); }); -Then(/^I can see the (\w+) option available$/, function(option) { +Then(/^I can see the (\w+) option available$/, async function(option) { option.should.to.be.oneOf(['delegate', 'reassign'], 'An unknown type was passed as argument'); if (option === 'delegate') { - this.ui.browser.documentTaskView.delegateOption.isVisible().should.be.true; + const delegateOption = await this.ui.browser.documentTaskView.delegateOption; + const delegateOptionVisible = await delegateOption.isVisible(); + delegateOptionVisible.should.be.true; } else if (option === 'reassign') { - this.ui.browser.documentTaskView.reassignOption.isVisible().should.be.true; + const reassignOption = await this.ui.browser.documentTaskView.reassignOption; + const reassignOptionVisible = await reassignOption.isVisible(); + reassignOptionVisible.should.be.true; } }); -Then(/^I can't see the (\w+) option available$/, function(option) { +Then(/^I can't see the (\w+) option available$/, async function(option) { option.should.to.be.oneOf(['delegate', 'reassign'], 'An unknown type was passed as argument'); if (option === 'delegate') { - this.ui.browser.documentTaskView.delegateOption.isVisible().should.be.false; + const delegateOption = await this.ui.browser.documentTaskView.delegateOption; + const delegateOptionVisible = await delegateOption.isVisible(); + delegateOptionVisible.should.be.false; } else if (option === 'reassign') { - this.ui.browser.documentTaskView.reassignOption.isVisible().should.be.false; + const reassignOption = await this.ui.browser.documentTaskView.reassignOption; + const reassignOptionVisible = await reassignOption.isVisible(); + reassignOptionVisible.should.be.false; } }); -Then(/^I can see that "([^"]*)" belongs to (\w+) actors$/, function(user, option) { +Then(/^I can see that "([^"]*)" belongs to (\w+) actors$/, async function(user, option) { option.should.to.be.oneOf(['delegated', 'assigned'], 'An unknown type was passed as argument'); // Workaround to WDIO limitation - const { documentTaskView } = this.ui.browser; - documentTaskView.waitForVisible(); - documentTaskView.waitForVisible(`${option === 'delegated' ? '#delegatedActors' : '#assignedActors'} nuxeo-tags`); - - driver.waitUntil(() => { - const actorsElement = option === 'delegated' ? documentTaskView.delegatedActors : documentTaskView.assignedActors; - return documentTaskView.actorExists(actorsElement, user); - }); + const browser = await this.ui.browser; + const documentTaskView = await browser.documentTaskView; + await documentTaskView.waitForVisible(); + await documentTaskView.waitForVisible( + `${option === 'delegated' ? '#delegatedActors' : '#assignedActors'} nuxeo-tags`, + ); + const delegatedActors = await documentTaskView.delegatedActors; + const assignedActors = await documentTaskView.assignedActors; + const actorsElement = option === 'delegated' ? delegatedActors : assignedActors; + const result = await documentTaskView.actorExists(actorsElement, user); + result.should.be.true; }); -Then('I can see the my task list has {int} item(s)', function(nb) { - this.ui.drawer.tasks.waitForVisible(); - driver.waitUntil(() => this.ui.drawer.tasks.nbItems === nb); +Then('I can see the my task list has {int} item(s)', async function(nb) { + await this.ui.drawer.tasks.waitForVisible(); + const result = await this.ui.drawer.tasks.nbItems; + if (result !== nb) { + throw Error(`Expected task count ${nb} but found ${result}`); + } }); -Then('I can perform the {string} task action', function(name) { - this.ui.browser.documentTaskView.performAction(name); +Then('I can perform the {string} task action', async function(name) { + await this.ui.browser.documentTaskView.performAction(name); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/trash.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/trash.js index c275fdeecd..bfa418336e 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/trash.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/trash.js @@ -1,4 +1,4 @@ -import { Given, Then, When } from '@cucumber/cucumber'; +import { Given, Then, When } from '../../node_modules/@cucumber/cucumber'; Given(/^I have the following trashed documents$/, (table) => { const tasks = table.rows().map((row) => () => { @@ -25,77 +25,110 @@ Given(/^I have a (.*) document trashed/, function(docType) { ); }); -Then('I can trash selected documents', function() { - this.ui.browser.selectionToolbar.waitForVisible(); - this.ui.browser.selectionToolbar.trashDocuments(); - driver.alertAccept(); - this.ui.browser.selectionToolbar.waitForNotVisible(); +Then('I can trash selected documents', async function() { + const browserEle = await this.ui.browser; + const toolBarEle = await browserEle.selectionToolbar; + await toolBarEle.waitForVisible(); + await toolBarEle.trashDocuments(); + await driver.alertAccept(); + await toolBarEle.waitForNotVisible(); + await driver.pause(3000); }); -Then('I cannot trash selected documents', function() { - this.ui.browser.selectionToolbar.waitForVisible(); - this.ui.browser.selectionToolbar.trashDocumentsButton.isVisible().should.be.false; +Then('I cannot trash selected documents', async function() { + const toolBarEle = await this.ui.browser.selectionToolbar; + await toolBarEle.waitForVisible(); + const trashDocbutton = await toolBarEle.trashDocumentsButton; + const buttonVisible = await trashDocbutton.isVisible(); + buttonVisible.should.be.false; }); -Then('I can permanently delete selected documents', function() { - this.ui.browser.selectionToolbar.waitForVisible(); - this.ui.browser.results.deleteDocuments(); - driver.alertAccept(); - this.ui.browser.selectionToolbar.waitForNotVisible(); +Then('I can permanently delete selected documents', async function() { + const toolBarEle = await this.ui.browser.selectionToolbar; + await toolBarEle.waitForVisible(); + const resultEle = await this.ui.browser.results; + await resultEle.deleteDocuments(); + await driver.alertAccept(); + await toolBarEle.waitForNotVisible(); }); -Then('I cannot permanently delete selected documents', function() { - this.ui.browser.selectionToolbar.waitForVisible(); - this.ui.browser.results.deleteDocumentsButton.isVisible().should.be.false; +Then('I cannot permanently delete selected documents', async function() { + const toolBarEle = await this.ui.browser.selectionToolbar; + await toolBarEle.waitForVisible(); + const resultEle = await this.ui.browser.results; + const deleteDocButton = await resultEle.deleteDocumentsButton; + const buttonVisible = await deleteDocButton.isVisible(); + buttonVisible.should.be.false; }); -Then('I can untrash selected documents', function() { - this.ui.browser.selectionToolbar.waitForVisible(); - this.ui.browser.results.untrashDocuments(); - driver.alertAccept(); - this.ui.browser.selectionToolbar.waitForNotVisible(); +Then('I can untrash selected documents', async function() { + const toolBarEle = await this.ui.browser.selectionToolbar; + await toolBarEle.waitForVisible(); + const resultEle = await this.ui.browser.results; + await resultEle.untrashDocuments(); + await driver.alertAccept(); + await toolBarEle.waitForNotVisible(); + await driver.pause(3000); }); -Then('I cannot untrash selected documents', function() { - this.ui.browser.selectionToolbar.waitForVisible(); - this.ui.browser.results.untrashDocumentsButton.isVisible().should.be.false; +Then('I cannot untrash selected documents', async function() { + const toolBarEle = await this.ui.browser.selectionToolbar; + await toolBarEle.waitForVisible(); + const resultEle = await this.ui.browser.results; + const untrashDocButton = await resultEle.untrashDocumentsButton; + const buttonVisible = await untrashDocButton.isVisible(); + buttonVisible.should.be.false; }); -Then('I can trash current document', function() { - const el = this.ui.browser.trashDocumentButton; - el.waitForVisible(); - el.click(); - driver.alertAccept(); +Then('I can trash current document', async function() { + const el = await this.ui.browser.trashDocumentButton; + await el.waitForVisible(); + await el.click(); + await driver.alertAccept(); }); -Then('I cannot trash current document', function() { - this.ui.browser.trashDocumentButton.isExisting().should.be.false; +Then('I cannot trash current document', async function() { + const trashButton = await this.ui.browser.trashDocumentButton; + const buttonVisible = await trashButton.isExisting(); + buttonVisible.should.be.false; }); -Then('I can untrash current document', function() { - this.ui.browser.trashedInfobar.waitForVisible(); - const el = this.ui.browser.untrashDocumentButton; - el.waitForVisible(); - el.click(); - driver.waitUntil(() => !this.ui.browser.trashedInfobar.isVisible()); +Then('I can untrash current document', async function() { + const infoBarEle = await this.ui.browser.trashedInfobar; + await infoBarEle.waitForVisible(); + const el = await this.ui.browser.untrashDocumentButton; + await el.waitForVisible(); + await el.click(); + await driver.pause(1000); + const infoVisible = await infoBarEle.isVisible(); + if (infoVisible) { + throw Error('Document is not untrashed'); + } }); -Then('I cannot untrash current document', function() { - this.ui.browser.untrashDocumentButton.isExisting().should.be.false; +Then('I cannot untrash current document', async function() { + const trashDocEle = await this.ui.browser.untrashDocumentButton; + const docVisible = await trashDocEle.isExisting(); + docVisible.should.be.false; }); -Then('I can permanently delete current document', function() { - this.ui.browser.trashedInfobar.waitForVisible(); - const el = this.ui.browser.deleteDocumentButton; - el.waitForVisible(); - el.click(); - driver.alertAccept(); +Then('I can permanently delete current document', async function() { + const trashedToolbar = await this.ui.browser.trashedInfobar; + await trashedToolbar.waitForVisible(); + const el = await this.ui.browser.deleteDocumentButton; + await el.waitForVisible(); + await el.click(); + await driver.alertAccept(); }); -Then('I cannot permanently delete current document', function() { - this.ui.browser.deleteDocumentButton.isExisting().should.be.false; +Then('I cannot permanently delete current document', async function() { + const deleteDoc = await this.ui.browser.deleteDocumentButton; + const docVisible = await deleteDoc.isExisting(); + docVisible.should.be.false; }); -When(/^I perform a Trash Search for (.+)/, function(searchTerm) { - this.ui.trashSearchForm.search('fulltext', searchTerm); +When(/^I perform a Trash Search for (.+)/, async function(searchTerm) { + const searcFormEle = await this.ui.trashSearchForm; + await searcFormEle.search('fulltext', searchTerm); + await driver.pause(3000); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/ui.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/ui.js index 9d15b6f6c0..eb49114b68 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/ui.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/ui.js @@ -1,24 +1,33 @@ -import { Then, When } from '@cucumber/cucumber'; +import { Then, When } from '../../node_modules/@cucumber/cucumber'; -When('I click the {string} button', function(button) { - return this.ui.drawer.open(button); +When('I click the {string} button', async function(button) { + await driver.pause(2000); + const drawer = await this.ui.drawer; + const buttonToclick = await drawer.open(button); + return buttonToclick; }); -When('I select {string} from the View menu', function(option) { - return this.ui.view(option); + +When('I select {string} from the View menu', async function(option) { + const ui = await this.ui; + return ui.view(option); }); -When('I reload the page', function() { +When('I reload the page', async function() { // XXX temporary fix for async issue with activity feed; will be fixed when NXP-21771 is tackled - driver.pause(3000); - this.ui.reload(); - $('#logo').waitForVisible(); + await driver.pause(3000); + await this.ui.reload(); + await $('#logo').waitForVisible(); }); -Then('I can see {string} in the Activity feed', function(activity) { +Then('I can see {string} in the Activity feed', async function(activity) { // XXX temporary fix for async issue with activity feed; will be fixed when NXP-21771 is tackled - driver.pause(3000); - this.ui.activityFeed.waitForVisible(); - this.ui.activityFeed.getActivity(activity).waitForVisible().should.be.true; + await driver.pause(10000); + const activityFeed = await this.ui.activityFeed; + await activityFeed.waitForVisible(); + const activityTab = await activityFeed.getActivity(activity); + const activityTabVisible = await activityTab.waitForVisible(); + await activityTabVisible.should.be.true; }); -Then('I click the blob download button', function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.downloadButton.click(); +Then('I click the blob download button', async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + const button = await page.downloadButton; + await button.click(); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/upload.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/upload.js index 49af24fa23..2ba125e33e 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/upload.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/upload.js @@ -1,47 +1,64 @@ -import { Then } from '@cucumber/cucumber'; +import { Then } from '../../node_modules/@cucumber/cucumber'; -Then(/^I upload file "(.+)" as document content/, function(file) { - return fixtures.layouts.setValue(this.ui.browser.el.element('nuxeo-dropzone'), file); +Then(/^I upload file "(.+)" as document content/, async function(file) { + const element = await this.ui.browser.el.element('nuxeo-dropzone'); + await fixtures.layouts.setValue(element, file); }); -Then('I can see the blob replace button', function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.view.waitForVisible(); - page.view.waitForVisible('nuxeo-replace-blob-button').should.be.true; +Then('I can see the blob replace button', async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const view = await page.view; + await view.waitForVisible(); + const ele = await view.el.element('nuxeo-replace-blob-button'); + const result = await ele.waitForVisible(); + result.should.be.true; }); -Then("I can't see the blob replace button", function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.view.waitForVisible(); - page.view.el.element('nuxeo-replace-blob-button').waitForVisible(browser.options.waitforTimeout, true).should.be.true; +Then("I can't see the blob replace button", async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const view = await page.view; + await view.waitForVisible(); + const ele = await view.el.element('nuxeo-replace-blob-button'); + const result = await ele.waitForVisible(5000, true); + result.should.be.true; }); -Then('I can see the option to add new attachments', function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.metadata.waitForVisible(); - page.metadata.waitForVisible('nuxeo-dropzone').should.be.true; +Then('I can see the option to add new attachments', async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const metadata = await page.metadata; + await metadata.waitForVisible(); + const ele = await metadata.el.element('nuxeo-dropzone'); + const result = await ele.waitForVisible(); + result.should.be.true; }); -Then("I can't see the option to add new attachments", function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.metadata.waitForVisible(); - page.metadata.waitForNotVisible('nuxeo-dropzone').should.be.true; +Then("I can't see the option to add new attachments", async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const metadata = await page.metadata; + await metadata.waitForVisible(); + const result = await metadata.waitForNotVisible('nuxeo-dropzone'); + result.should.be.true; }); -Then('I can see the option to add a main blob', function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.view.waitForVisible(); - page.view.waitForVisible('nuxeo-dropzone').should.be.true; +Then('I can see the option to add a main blob', async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const view = await page.view; + await view.waitForVisible(); + const ele = await view.el.element('nuxeo-dropzone'); + const result = await ele.waitForVisible(); + result.should.be.true; }); -Then("I can't see the option to add a main blob", function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.view.waitForVisible(); - page.view.waitForNotVisible('nuxeo-dropzone').should.be.true; +Then("I can't see the option to add a main blob", async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const view = await page.view; + await view.waitForVisible(); + const result = await view.waitForNotVisible('nuxeo-dropzone'); + result.should.be.true; }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/user.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/user.js index 86d844208f..4c0900fb0b 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/user.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/user.js @@ -1,46 +1,63 @@ -import { Then, When } from '@cucumber/cucumber'; +import { Then, When } from '../../node_modules/@cucumber/cucumber'; -When(/^I select user from the dropdown menu$/, function() { - this.ui.user.dropdown.waitForVisible(); - this.ui.user.userItem.click(); +When(/^I select user from the dropdown menu$/, async function() { + const dropdownEle = await this.ui.user.dropdown; + await dropdownEle.waitForVisible(); + const itemEle = await this.ui.user.userItem; + await itemEle.click(); }); -When(/^I can see the new user form$/, function() { - this.ui.user.createUserForm.waitForVisible(); +When(/^I can see the new user form$/, async function() { + const formEle = await this.ui.user.createUserForm; + await formEle.waitForVisible(); }); -Then(/^I can create a user with the following properties:$/, function(table) { - this.ui.user.fillMultipleValues(table, this.ui.user.createUserDialog); - this.ui.user.createUserButton.click(); +Then(/^I can create a user with the following properties:$/, async function(table) { + await this.ui.user.fillMultipleValues(table, this.ui.user.createUserDialog); + const buttonEle = await this.ui.user.createUserButton; + await buttonEle.click(); }); -Then(/^I can search for the user "([^"]*)"$/, function(username) { - this.ui.user.searchFor(username); - this.ui.user.waitForVisible('nuxeo-card[name="users"] .table nuxeo-user-tag'); - this.ui.group.click('nuxeo-card[name="users"] .table nuxeo-user-tag'); - this.ui.group.waitForVisible('nuxeo-user-management'); - const user = this.ui.group.el.elements('.user.heading').find((e) => e.getText() === username); - user.waitForVisible().should.be.true; +Then(/^I can search for the user "([^"]*)"$/, async function(username) { + await this.ui.user.searchFor(username); + await this.ui.user.waitForVisible('nuxeo-card[name="users"] .table nuxeo-user-tag'); + const groupEle = await this.ui.group.el.$('nuxeo-card[name="users"] .table nuxeo-user-tag'); + await groupEle.click(); + await this.ui.group.waitForVisible('nuxeo-user-management'); + const user = await this.ui.group.el.elements('.user.heading'); + const userEle = await user.find(async (e) => (await e.getText()) === username); + const isVisible = await userEle.waitForVisible(); + isVisible.should.be.true; }); -Then(/^I can see the user has the email "([^"]*)"$/, function(userEmail) { - const user = this.ui.user.el.element('nuxeo-view-user [name="email"]'); - driver.waitUntil(() => user.element('span').getText() === userEmail); +Then(/^I can see the user has the email "([^"]*)"$/, async function(userEmail) { + const user = await this.ui.user.el.element('nuxeo-view-user [name="email"]'); + const ele = await user.element('span'); + const emailText = await ele.getText(); + if (emailText !== userEmail) { + throw Error("I can't see the expected email for user"); + } }); -Then(/^I can edit the user "([^"]*)" with the following properties:$/, function(username, table) { - this.ui.user.searchFor(username); - this.ui.user.searchResult(username).click(); - this.ui.user.editUserButton.waitForVisible(); - this.ui.user.editUserButton.click(); - this.ui.user.fillMultipleValues(table, this.ui.user.editUserDialog); - this.ui.user.editUserDialogButton.click(); +Then(/^I can edit the user "([^"]*)" with the following properties:$/, async function(username, table) { + await this.ui.user.searchFor(username); + const resultEle = await this.ui.user.searchResult(username); + await resultEle.click(); + const editButton = await this.ui.user.editUserButton; + await editButton.waitForVisible(); + await editButton.click(); + await this.ui.user.fillMultipleValues(table, this.ui.user.editUserDialog); + const dialogButton = await this.ui.user.editUserDialogButton; + await dialogButton.click(); }); -Then(/^I can delete the user "([^"]*)"$/, function(username) { - this.ui.user.searchFor(username); - this.ui.user.searchResult(username).click(); - this.ui.user.deleteUserButton.waitForVisible(); - this.ui.user.deleteUserButton.click(); - this.ui.user.confirmDeleteUserButton.click(); +Then(/^I can delete the user "([^"]*)"$/, async function(username) { + await this.ui.user.searchFor(username); + const result = await this.ui.user.searchResult(username); + await result.click(); + const buttonEle = await this.ui.user.deleteUserButton; + await buttonEle.waitForVisible(); + await buttonEle.click(); + const confirmButton = await this.ui.user.confirmDeleteUserButton; + await confirmButton.click(); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/user_settings.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/user_settings.js index 2bc59e8ba0..d5615c927b 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/user_settings.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/user_settings.js @@ -1,4 +1,4 @@ -import { Given, Then, When } from '@cucumber/cucumber'; +import { Given, Then, When } from '../../node_modules/@cucumber/cucumber'; /* Cloud Services */ @@ -10,28 +10,32 @@ Given(/^I have tokens for the following OAuth2 providers$/, function(table) { return Promise.all(table.rows().map((row) => fixtures.oauth2Providers.createToken(row[0], this.username))); }); -When(/^I am on user cloud services page$/, function() { - return this.ui.goToUserCloudServices(); +When(/^I am on user cloud services page$/, async function() { + const cloudServicesEle = await this.ui.goToUserCloudServices(); + return cloudServicesEle; }); -Then(/^I can only see (\d+) provider token[s]? that belong[s]? to me$/, function(numberOfTokens) { - this.ui.userCloudServices.waitForVisible(); - driver.waitUntil(() => this.ui.userCloudServices.getTokens(this.username).length === numberOfTokens); +Then(/^I can only see (\d+) provider token[s]? that belong[s]? to me$/, async function(numberOfTokens) { + const cloudService = await this.ui.userCloudServices; + await cloudService.waitForVisible(); + const tokenEle = await cloudService.getTokens(this.username); + if (tokenEle.length !== numberOfTokens) { + throw Error('Provider token no.s are not as expected'); + } }); -Then(/^I can delete token for provider "(.+)" that belongs to me$/, function(provider) { - this.ui.userCloudServices.waitForVisible(); - let tokens; - driver.waitUntil(() => { - tokens = this.ui.userCloudServices.getTokens(this.username, provider); - return tokens.length === 1; - }); - const deleteButton = tokens[0].deleteButton(); - deleteButton.waitForVisible(); - deleteButton.click(); - driver.alertAccept(); - this.ui.userCloudServices.waitForVisible(); - driver.waitUntil(() => this.ui.userCloudServices.getTokens(this.username, provider).length === 0); +Then(/^I can delete token for provider "(.+)" that belongs to me$/, async function(provider) { + const cloudServicePage = await this.ui.userCloudServices; + await cloudServicePage.waitForVisible(); + const tokenEle = await cloudServicePage.getTokens(this.username, provider); + tokenEle.length.should.be.equal(1); + const deleteButton = await tokenEle[0].deleteButton(); + await deleteButton.waitForVisible(); + await deleteButton.click(); + await driver.alertAccept(); + await cloudServicePage.waitForVisible(); + const tokenAfterDelete = await cloudServicePage.getTokens(this.username, provider); + tokenAfterDelete.length.should.be.equal(0); }); /* Authorized Applications */ @@ -44,8 +48,8 @@ Given(/^I have tokens for the following OAuth2 clients$/, function(table) { return Promise.all(table.rows().map((row) => fixtures.oauth2Clients.createToken(row[0], this.username))); }); -When(/^I am on user authorized applications page$/, function() { - this.ui.goToUserAuthorizedApps(); +When(/^I am on user authorized applications page$/, async function() { + await this.ui.goToUserAuthorizedApps(); }); Then(/^I can see "(.+)" as an authorized application$/, function(application) { @@ -57,23 +61,35 @@ Then(/^I can see "(.+)" as an authorized application$/, function(application) { }); }); -Then(/^I can only see (\d+) authorized application[s]?$/, function(numberOfApps) { - driver.waitUntil(() => this.ui.userAuthorizedApps.getApps().length === numberOfApps); +Then(/^I can only see (\d+) authorized application[s]?$/, async function(numberOfApps) { + await driver.pause(3000); + const authPage = await this.ui.userAuthorizedApps; + await authPage.waitForVisible(); + const apps = await authPage.getApps(); + if (apps.length !== numberOfApps) { + throw Error(`Expected app count should be ${numberOfApps} but found ${apps.length}`); + } }); Then('I cannot see authorized application', function() { this.ui.emptyAuthorizedApps.waitForDisplayed(); }); -Then(/^I can revoke access for "(.+)" application$/, function(appName) { - this.ui.userAuthorizedApps.waitForVisible(); - browser.waitUntil(() => this.ui.userAuthorizedApps.getApps().length > 0); - const apps = this.ui.userAuthorizedApps.getApps(appName); - apps.length.should.equal(1); - const revokeButton = apps[0].revokeButton(); - revokeButton.waitForVisible(); - revokeButton.click(); - driver.alertAccept(); - this.ui.userAuthorizedApps.waitForVisible(); - driver.waitUntil(() => this.ui.userAuthorizedApps.getApps(appName).length === 0); +Then(/^I can revoke access for "(.+)" application$/, async function(appName) { + const authPage = await this.ui.userAuthorizedApps; + await authPage.waitForVisible(); + const apps = await authPage.getApps(); + await browser.waitUntil(() => apps.length > 0); + const appRevoke = await authPage.getApps(appName); + appRevoke.length.should.equal(1); + const app = await appRevoke[0]; + const revokeButton = await app.revokeButton(); + await revokeButton.waitForVisible(); + await revokeButton.click(); + await driver.alertAccept(); + await authPage.waitForVisible(); + const appResults = await authPage.getApps(appName); + if (appResults.length !== 0) { + throw Error(`Expected app count should be 0 but found ${appResults.length}`); + } }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/versions.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/versions.js index 8d71e0d64f..121da18857 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/versions.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/versions.js @@ -1,123 +1,154 @@ -import { When } from '@cucumber/cucumber'; +import { When } from '../../node_modules/@cucumber/cucumber'; -When(/^I can see the version info bar with text "(.*)"$/, function(text) { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.versionInfoBar.waitForVisible(); - page.versionInfoBar.getText().should.equal(text); +When(/^I can see the version info bar with text "(.*)"$/, async function(text) { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const versionInfoBar = await page.versionInfoBar; + await versionInfoBar.waitForVisible(); + const versionInfoBarText = await versionInfoBar.getText(); + versionInfoBarText.should.equal(text); }); -When(/^The document is unversioned$/, function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.versions.waitForVisible(); - page.versions.createVersionButton.waitForVisible(); +When(/^The document is unversioned$/, async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + await page.versions.waitForVisible(); + const createVersionBtn = await page.versions.createVersionButton; + await createVersionBtn.waitForVisible(); }); -When(/^I click the Create Version button$/, function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.versions.waitForVisible(); - page.versions.createVersionButton.waitForVisible(); - page.versions.createVersionButton.click(); +When(/^I click the Create Version button$/, async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + await page.versions.waitForVisible(); + const createVersionBtn = await page.versions.createVersionButton; + await createVersionBtn.waitForVisible(); + await createVersionBtn.click(); }); -When(/^The create version dialog appears$/, function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.versions.waitForVisible(); - page.versions.dialog.waitForVisible(); - page.versions.dialog.waitForVisible('paper-button[dialog-dismiss]'); - page.versions.dialog.waitForVisible('paper-button[dialog-confirm]'); +When(/^The create version dialog appears$/, async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + await page.versions.waitForVisible(); + const pageVersionDialog = await page.versions.dialog; + await pageVersionDialog.waitForVisible(); + await pageVersionDialog.waitForVisible('paper-button[dialog-dismiss]'); + await pageVersionDialog.waitForVisible('paper-button[dialog-confirm]'); }); -When(/^Version options (\d+)\.(\d+) and (\d+)\.(\d+) are presented$/, function(v1, v2, v3, v4) { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.versions.waitForVisible(); - page.versions.dialog.waitForVisible(); - page.versions.dialogNextMinor.getText().should.equal(`${v1}.${v2}`); - page.versions.dialogNextMajor.getText().should.equal(`${v3}.${v4}`); +When(/^Version options (\d+)\.(\d+) and (\d+)\.(\d+) are presented$/, async function(v1, v2, v3, v4) { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + await page.versions.waitForVisible(); + const pageVersionDialog = await page.versions.dialog; + await pageVersionDialog.waitForVisible(); + const dialogMinor = await page.versions.dialogNextMinor; + const dialogMinorText = await dialogMinor.getText(); + dialogMinorText.should.equal(`${v1}.${v2}`); + const dialogMajor = await page.versions.dialogNextMajor; + const dialogMajorText = await dialogMajor.getText(); + dialogMajorText.should.equal(`${v3}.${v4}`); }); -When(/^I create a (major|minor) version$/, function(versionType) { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.versions.waitForVisible(); - page.versions.dialog.waitForVisible(); +When(/^I create a (major|minor) version$/, async function(versionType) { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + await page.versions.waitForVisible(); + const pageVersionDialog = await page.versions.dialog; + await pageVersionDialog.waitForVisible(); switch (versionType) { - case 'major': - page.versions.dialogMajorOption.click(); + case 'major': { + const dialogMajorOpt = await page.versions.dialogMajorOption; + await dialogMajorOpt.click(); break; - case 'minor': - page.versions.dialogMinorOption.click(); + } + case 'minor': { + const dialogMinorOpt = await page.versions.dialogMinorOption; + await dialogMinorOpt.click(); break; + } default: // do nothing } - page.versions.dialogConfirmButton.waitForVisible(); - page.versions.dialogConfirmButton.click(); + const dialogConfirmBtn = await page.versions.dialogConfirmButton; + await dialogConfirmBtn.waitForVisible(); + await dialogConfirmBtn.click(); }); -When(/^The document version is ([^"]*)$/, function(label) { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.versions.waitForVisible(); - page.versions.toggle.waitForVisible(); - driver.waitUntil(() => page.versions.toggle.getText() === label, `No version found with label "${label}"`); +When(/^The document version is ([^"]*)$/, async function(label) { + await driver.pause(1000); + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + await page.versions.waitForVisible(); + const versionsToggle = await page.versions.toggle; + await versionsToggle.waitForVisible(); + const versionsToggleText = await versionsToggle.getText(); + if (versionsToggleText !== label) { + throw Error(`No version found with label "${label}"`); + } }); -When(/^I click the versions list$/, function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.versions.waitForVisible(); - page.versions.toggle.waitForVisible(); - page.versions.toggle.click(); - page.versions.listItems.waitForVisible(); +When(/^I click the versions list$/, async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const versions = await page.versions; + await versions.waitForVisible(); + const versionsToggle = await versions.toggle; + await versionsToggle.waitForVisible(); + await versionsToggle.click(); + const versionsListItems = await versions.listItems; + await versionsListItems.waitForVisible(); }); -When(/^I click the versions list at index (\d+)$/, function(index) { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.versions.waitForVisible(); - page.versions.listItem(index).waitForExist(); - page.versions.listItems.waitForVisible(); - page.versions.listItem(index).waitForExist(); - page.versions.listItem(index).waitForVisible(); - page.versions.listItem(index).click(); +When(/^I click the versions list at index (\d+)$/, async function(index) { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const versions = await page.versions; + await versions.waitForVisible(); + await versions.listItem(index).waitForExist(); + await versions.listItems.waitForVisible(); + await versions.listItem(index).waitForExist(); + await versions.listItem(index).waitForVisible(); + await versions.listItem(index).click(); }); -When(/^Versions item index at (\d+) is ([^"]*)$/, function(index, text) { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.versions.waitForVisible(); - page.versions - .listItemTitle(index) - .getText() - .should.equals(text); +When(/^Versions item index at (\d+) is ([^"]*)$/, async function(index, text) { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const versions = await page.versions; + await versions.waitForVisible(); + const listItemTitle = await versions.listItemTitle(index); + const listItemTitleText = await listItemTitle.getText(); + listItemTitleText.should.equals(text); }); -When(/^Versions count is (\d+)$/, function(count) { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.versions.waitForVisible(); - page.versions.listCount.should.equal(count); +When(/^Versions count is (\d+)$/, async function(count) { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const versions = await page.versions; + await versions.waitForVisible(); + const listCount = await versions.listCount; + listCount.should.equal(count); }); -When(/^I click the Create Version button in versions list$/, function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.versions.waitForVisible(); - page.versions.listItems.waitForVisible(); - page.versions.listCreateVersionButton.waitForVisible(); - page.versions.listCreateVersionButton.click(); +When(/^I click the Create Version button in versions list$/, async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const versions = await page.versions; + await versions.waitForVisible(); + await versions.listItems.waitForVisible(); + const listCreateVersionButton = await versions.listCreateVersionButton; + await listCreateVersionButton.waitForVisible(); + await listCreateVersionButton.click(); }); -When(/^I can restore version$/, function() { - const page = this.ui.browser.documentPage(this.doc.type); - page.waitForVisible(); - page.restoreVersionButton.waitForVisible(); - page.restoreVersionButton.click(); - page.restoreVersionButtonConfirm.waitForVisible(); - page.restoreVersionButtonConfirm.click(); +When(/^I can restore version$/, async function() { + const page = await this.ui.browser.documentPage(this.doc.type); + await page.waitForVisible(); + const restoreVersionButton = await page.restoreVersionButton; + await restoreVersionButton.waitForVisible(); + await restoreVersionButton.click(); + const restoreVersionButtonConfirm = await page.restoreVersionButtonConfirm; + await restoreVersionButtonConfirm.waitForVisible(); + await restoreVersionButtonConfirm.click(); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/video.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/video.js index 430f3ce1f1..91605bc7a2 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/video.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/video.js @@ -1,26 +1,37 @@ -import { Then } from '@cucumber/cucumber'; +import { Then } from '../../node_modules/@cucumber/cucumber'; -Then('I can see the video conversions panel', function() { - const page = this.ui.browser.documentPage(this.doc.type); +Then('I can see the video conversions panel', async function() { + const uiBrowser = await this.ui.browser; + const page = await uiBrowser.documentPage(this.doc.type); page.waitForVisible(); - page.el.element('nuxeo-video-conversions').waitForVisible().should.be.true; + const element = await page.el.$('nuxeo-video-conversions'); + const elementVisible = await element.waitForVisible(); + await elementVisible.should.be.true; }); -Then('I can see the video storyboard', function() { - driver.waitUntil(() => { - const page = this.ui.browser.documentPage(this.doc.type); - if (!page.isVisible()) { - return false; - } - const videoViewer = page.el.element('nuxeo-video-viewer'); - if (!videoViewer.isVisible()) { - return false; - } - if (videoViewer.element('#storyboard').isVisible() !== true) { - driver.execute(() => Nuxeo.UI.app.refresh()); - driver.pause(1000); - return false; - } - return true; - }); +Then('I can see the video storyboard', async function() { + driver.waitUntil( + async () => { + const uiBrowser = await this.ui.browser; + const page = await uiBrowser.documentPage(this.doc.type); + if (!page.isVisible()) { + return false; + } + const videoViewer = await page.el.element('nuxeo-video-viewer'); + if (!videoViewer.isVisible()) { + return false; + } + const storyBoard = await videoViewer.element('#storyboard'); + const boardVisible = await storyBoard.isVisible(); + if (boardVisible !== true) { + await driver.execute(async () => Nuxeo.UI.app.refresh()); + await driver.pause(1000); + return false; + } + return true; + }, + { + timeoutMsg: 'I cannot see the video storyboard', + }, + ); }); diff --git a/packages/nuxeo-web-ui-ftest/features/step_definitions/vocabularies.js b/packages/nuxeo-web-ui-ftest/features/step_definitions/vocabularies.js index 2e4e23ea54..47b5c6a874 100644 --- a/packages/nuxeo-web-ui-ftest/features/step_definitions/vocabularies.js +++ b/packages/nuxeo-web-ui-ftest/features/step_definitions/vocabularies.js @@ -1,65 +1,93 @@ -import { Given, Then, When } from '@cucumber/cucumber'; +import { Given, Then, When } from '../../node_modules/@cucumber/cucumber'; -Given('I am on vocabulary page', function() { - return this.ui.administration.goToVocabularyManagement(); +Given('I am on vocabulary page', async function() { + const administration = await this.ui.administration; + const vocabularyPage = await administration.goToVocabularyManagement(); + return vocabularyPage; }); -When('I select {string} vocabulary', function(name) { - this.ui.administration.waitForVisible(); - this.ui.administration.vocabularyManagement.waitForVisible(); - this.ui.administration.vocabularyManagement.vocabulary(name); +When('I select {string} vocabulary', async function(name) { + const administration = await this.ui.administration; + await administration.waitForVisible(); + const vocabularyManagement = await administration.vocabularyManagement; + await vocabularyManagement.waitForVisible(); + await vocabularyManagement.vocabulary(name); }); -Then('I can add {string} entry', function(id) { - this.ui.administration.waitForVisible(); - this.ui.administration.vocabularyManagement.waitForVisible(); - this.ui.administration.vocabularyManagement.addNewEntry(id, id); +Then('I can add {string} entry', async function(id) { + const administration = await this.ui.administration; + await administration.waitForVisible(); + const vocabularyManagement = await administration.vocabularyManagement; + await vocabularyManagement.waitForVisible(); + await vocabularyManagement.addNewEntry(id, id); }); -Then('I can see the vocabulary table', function() { - this.ui.administration.waitForVisible(); - this.ui.administration.vocabularyManagement.waitForVisible(); - this.ui.administration.vocabularyManagement.isVocabularyTableVisible.should.be.true; +Then('I can see the vocabulary table', async function() { + const administration = await this.ui.administration; + await administration.waitForVisible(); + const vocabularyManagement = await administration.vocabularyManagement; + await vocabularyManagement.waitForVisible(); + const isVocabularyTableVisible = await vocabularyManagement.isVocabularyTableVisible; + isVocabularyTableVisible.should.be.true; }); -Then('I have a non empty table', function() { - this.ui.administration.waitForVisible(); - this.ui.administration.vocabularyManagement.waitForVisible(); - this.ui.administration.vocabularyManagement.isVocabularyTableFilled.should.be.true; +Then('I have a non empty table', async function() { + const administration = await this.ui.administration; + await administration.waitForVisible(); + const vocabularyManagement = await administration.vocabularyManagement; + await vocabularyManagement.waitForVisible(); + const isVocabularyTableFilled = await vocabularyManagement.isVocabularyTableFilled; + isVocabularyTableFilled.should.be.true; }); -Then('I can see {string} entry', function(name) { - this.ui.administration.waitForVisible(); - this.ui.administration.vocabularyManagement.waitForVisible(); - this.ui.administration.vocabularyManagement.waitForHasEntry(name).should.be.true; +Then('I can see {string} entry', async function(name) { + const administration = await this.ui.administration; + await administration.waitForVisible(); + const vocabularyManagement = await administration.vocabularyManagement; + await vocabularyManagement.waitForVisible(); + const hasEntry = await vocabularyManagement.waitForHasEntry(name); + hasEntry.should.be.true; }); -Then('I cannot see {string} entry', function(name) { - this.ui.administration.waitForVisible(); - this.ui.administration.vocabularyManagement.waitForVisible(); - this.ui.administration.vocabularyManagement.waitForHasEntry(name, true).should.be.true; +Then('I cannot see {string} entry', async function(name) { + const administration = await this.ui.administration; + await administration.waitForVisible(); + const vocabularyManagement = await administration.vocabularyManagement; + await vocabularyManagement.waitForVisible(); + const hasNoEntry = await vocabularyManagement.waitForHasEntry(name, true); + hasNoEntry.should.be.true; }); -Then('I can delete entry with index {int}', function(index) { - this.ui.administration.waitForVisible(); - this.ui.administration.vocabularyManagement.waitForVisible(); - this.ui.administration.vocabularyManagement.deleteEntry(index); +Then('I can delete entry with index {int}', async function(index) { + const administration = await this.ui.administration; + await administration.waitForVisible(); + const vocabularyManagement = await administration.vocabularyManagement; + await vocabularyManagement.waitForVisible(); + await vocabularyManagement.deleteEntry(index); }); -Then('I can edit entry with index {int} and new label {string}', function(index, label) { - this.ui.administration.waitForVisible(); - this.ui.administration.vocabularyManagement.waitForVisible(); - this.ui.administration.vocabularyManagement.editEntry(index, label); +Then('I can edit entry with index {int} and new label {string}', async function(index, label) { + const administration = await this.ui.administration; + await administration.waitForVisible(); + const vocabularyManagement = await administration.vocabularyManagement; + await vocabularyManagement.waitForVisible(); + await vocabularyManagement.editEntry(index, label); }); -Then('I can see edit dialog', function() { - this.ui.administration.waitForVisible(); - this.ui.administration.vocabularyManagement.waitForVisible(); - this.ui.administration.vocabularyManagement.hasEditDialog.should.be.true; +Then('I can see edit dialog', async function() { + const administration = await this.ui.administration; + await administration.waitForVisible(); + const vocabularyManagement = await administration.vocabularyManagement; + await vocabularyManagement.waitForVisible(); + const hasEditDialog = await vocabularyManagement.hasEditDialog(); + hasEditDialog.should.be.true; }); -Then('I can see create dialog', function() { - this.ui.administration.waitForVisible(); - this.ui.administration.vocabularyManagement.waitForVisible(); - this.ui.administration.vocabularyManagement.hasCreateDialog.should.be.true; +Then('I can see create dialog', async function() { + const administration = await this.ui.administration; + await administration.waitForVisible(); + const vocabularyManagement = await administration.vocabularyManagement; + await vocabularyManagement.waitForVisible(); + const hasCreateDialog = await vocabularyManagement.hasCreateDialog(); + await hasCreateDialog.should.be.true; }); diff --git a/packages/nuxeo-web-ui-ftest/package.json b/packages/nuxeo-web-ui-ftest/package.json index 6d38af0dc4..297073f352 100644 --- a/packages/nuxeo-web-ui-ftest/package.json +++ b/packages/nuxeo-web-ui-ftest/package.json @@ -11,20 +11,17 @@ }, "license": "Apache-2.0", "engines": { - "node": ">=10.23.0 <15.0.0" + "node": ">=18.0.0" }, "dependencies": { "@babel/core": "^7.15.0", "@babel/preset-env": "^7.15.0", "@babel/register": "^7.14.5", - "@cucumber/cucumber": "^7.0.0", "@cucumber/tag-expressions": "^2.0.4", - "@wdio/cli": "7.20.5", - "@wdio/cucumber-framework": "^7.20.3", - "@wdio/local-runner": "^7.2.0", - "@wdio/selenium-standalone-service": "7.2.0", - "@wdio/spec-reporter": "^7.2.0", - "@wdio/sync": "^7.2.0", + "@wdio/cli": "^8.16.11", + "@wdio/cucumber-framework": "^8.16.11", + "@wdio/local-runner": "^8.16.11", + "@wdio/spec-reporter": "^8.16.9", "babel-plugin-transform-rename-import": "^2.3.0", "babel-preset-env": "^1.7.0", "babel-register": "^6.26.0", @@ -36,12 +33,12 @@ "fs-finder": "^1.8.1", "minimist": "^1.2.0", "mkdirp": "^0.5.1", - "moment": "^2.22.0", + "moment": "^2.29.4", "multiple-cucumber-html-reporter": "^1.18.0", "node-fetch": "^2.6.1", "nuxeo": "^4.0.3", - "wdio-chromedriver-service": "^7.0.0", - "wdio-cucumberjs-json-reporter": "^2.0.3", - "webdriverio": "^7.2.0" + "wdio-chromedriver-service": "^8.1.1", + "wdio-cucumberjs-json-reporter": "^5.1.7", + "webdriverio": "8.20.4" } -} +} \ No newline at end of file diff --git a/packages/nuxeo-web-ui-ftest/pages/base.js b/packages/nuxeo-web-ui-ftest/pages/base.js index 9ddefb9726..216faf1c50 100644 --- a/packages/nuxeo-web-ui-ftest/pages/base.js +++ b/packages/nuxeo-web-ui-ftest/pages/base.js @@ -19,7 +19,12 @@ export default class BasePage { return this.el.waitForVisible(...args); } - waitForNotVisible(selector) { - return this.waitForVisible(...[selector].filter(Boolean).concat([browser.options.waitForTimeout, true])); + async waitForNotVisible(selector) { + if (selector) { + const ele = await this.el.$(...[selector].filter(Boolean).concat([browser.options.waitForTimeout, true])); + const isSelectorVisible = await this.waitForVisible(ele); + return isSelectorVisible; + } + return false; } } diff --git a/packages/nuxeo-web-ui-ftest/pages/helpers.js b/packages/nuxeo-web-ui-ftest/pages/helpers.js index 86124f104d..8e5b11a7de 100644 --- a/packages/nuxeo-web-ui-ftest/pages/helpers.js +++ b/packages/nuxeo-web-ui-ftest/pages/helpers.js @@ -5,31 +5,31 @@ const _flushProperties = () => { }, global.config || []); }; -const refresh = () => { - driver.refresh(); - _flushProperties(); +const refresh = async () => { + await driver.refresh(); + await _flushProperties(); }; -const url = (...args) => { - driver.url(...args); +const url = async (...args) => { + await driver.url(...args); _flushProperties(); }; -const clickActionMenu = (menu, selector) => { - menu.waitForExist(selector); - const action = menu.element(selector); - action.waitForExist(); - if (action.getAttribute('show-label') !== null) { +const clickActionMenu = async (menu, selector) => { + const action = await menu.$(selector); + await action.waitForExist(); + if ((await action.getAttribute('show-label')) !== null) { // if the element is inside the dropdown, we need to expand it - menu.click('#dropdownButton'); - menu.waitForVisible('paper-listbox'); - menu.waitForVisible('[slot="dropdown"] .label'); - menu.waitForEnabled('[slot="dropdown"] .label'); + const myButton = await menu.$('#dropdownButton'); + await myButton.click(); + await menu.waitForVisible('paper-listbox'); + await menu.waitForVisible('[slot="dropdown"] .label'); + await menu.waitForEnabled('[slot="dropdown"] .label'); } - action.waitForVisible('.action'); - action.waitForEnabled('.action'); - // let's make sure we're clicking on the div the has the click event handler - action.click('.action'); + const myClass = await action.$('.action'); + await myClass.waitForVisible(); + await myClass.waitForEnabled(); + await myClass.click(); }; export { clickActionMenu, refresh, url }; diff --git a/packages/nuxeo-web-ui-ftest/pages/login.js b/packages/nuxeo-web-ui-ftest/pages/login.js index 6d62069bf2..e9846867bf 100644 --- a/packages/nuxeo-web-ui-ftest/pages/login.js +++ b/packages/nuxeo-web-ui-ftest/pages/login.js @@ -1,22 +1,25 @@ export default class Login { - set username(username) { - $('#username').waitForDisplayed(); - $('#username').setValue(username); + async username(username) { + const inputUserName = await $('#username'); + await inputUserName.setValue(username); } - set password(password) { - $('#password').waitForDisplayed(); - $('#password').setValue(password); + async password(password) { + const inputPassword = await $('#password'); + await inputPassword.setValue(password); } - submit() { - $('[name="Submit"]').waitForDisplayed(); - return $('[name="Submit"]').click(); + async submit() { + const submitButton = await $('[name="Submit"]'); + await submitButton.click(); } static get() { - const baseUrl = process.env.NUXEO_URL || ''; - driver.url(baseUrl ? `${baseUrl}/logout` : 'logout'); - return new this(); + return (async () => { + const baseUrl = (await process.env.NUXEO_URL) || ''; + await driver.pause(1000); + await browser.url(baseUrl ? `${baseUrl}/logout` : 'logout'); + return new this(); + })(); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/spreadsheet.js b/packages/nuxeo-web-ui-ftest/pages/spreadsheet.js new file mode 100644 index 0000000000..c181d97625 --- /dev/null +++ b/packages/nuxeo-web-ui-ftest/pages/spreadsheet.js @@ -0,0 +1,94 @@ +export default class Spreadsheet { + constructor() { + driver.waitUntil(() => driver.execute(() => window.spreadheet)); + } + + element(...params) { + return driver.element(...params); + } + + get table() { + return (async () => { + const tableEle = await this.element('table.htCore'); + return tableEle; + })(); + } + + get headers() { + return (async () => { + try { + const table = await this.table; + const headerElements = await table.elements('thead span'); + const headerElementArray = Array.from(headerElements); + const header = await Promise.all(headerElementArray.map(async (e) => e.getText())); + return header; + } catch (error) { + console.error('Error fetching headers:', error); + return []; + } + })(); + } + + get rows() { + return (async () => { + const tableEle = await this.table.elements('tbody tr'); + return tableEle; + })(); + } + + get console() { + return (async () => { + const consoleEle = await this.element('#console'); + return consoleEle; + })(); + } + + /** + * Set data at given row and cell + */ + async setData(row, cell, data) { + await this._callHandsontable('setDataAtCell', row, cell, data); + } + + /** + * Get data at given row and cell + */ + async getData(row, cell) { + return (async () => { + const getDataCell = await this._callHandsontable('getDataAtCell', row, cell); + return getDataCell; + })(); + } + + /** + * Save the data + */ + async save() { + const saveButton = await this.element('#save'); + if (saveButton) { + await saveButton.click(); + } else { + console.error('Save button not found!!'); + } + } + + /** + * Close the spreadsheet + */ + async close() { + const closeButton = await this.element('#close'); + if (closeButton) { + await closeButton.click(); + } else { + console.error('Close button not found!!'); + } + } + + /** + * Call a Handsontable method + */ + async _callHandsontable(method, ...params) { + // eslint-disable-next-line no-undef, no-shadow + await driver.execute((method, ...params) => window.spreadsheet.ht[method](...params), method, ...params); + } +} diff --git a/packages/nuxeo-web-ui-ftest/pages/ui.js b/packages/nuxeo-web-ui-ftest/pages/ui.js index c36201b1ed..d22c27ba7d 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui.js @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop */ import Browser from './ui/browser'; import CreateDialog from './ui/create_dialog'; import Drawer from './ui/drawer'; @@ -15,19 +16,25 @@ import UserCloudServices from './ui/oauth2/user_cloud_services'; import { refresh, url } from './helpers'; export default class UI extends BasePage { - goHome() { - this.drawer.logo.click(); + async goHome() { + const logoEle = await this.drawer.logo; + await logoEle.waitForVisible(); + await logoEle.click(); } - reload() { - refresh(); + async reload() { + await refresh(); } get activityFeed() { - $('nuxeo-document-page nuxeo-page-item[name="activity"]').waitForVisible(); - browser.click('nuxeo-document-page nuxeo-page-item[name="activity"]'); - $('nuxeo-document-activity').waitForVisible(); - return new ActivityFeed('nuxeo-document-activity'); + return (async () => { + await $('nuxeo-document-page nuxeo-page-item[name="activity"]').waitForVisible(); + browser.click('nuxeo-document-page nuxeo-page-item[name="activity"]'); + await this.reload(); + await $('nuxeo-document-activity').waitForVisible(); + const activity = new ActivityFeed('nuxeo-document-activity'); + return activity; + })(); } get historyTable() { @@ -55,14 +62,19 @@ export default class UI extends BasePage { } get searchButton() { - return this.el.element('#searchButton'); + return this.el.$('#searchButton'); } get results() { - if (this.el.element('nuxeo-browser').isVisible()) { - return this.browser.results; - } - return new Search('nuxeo-search-results-layout[id="results"]'); + return (async () => { + const ele = await this.el.element('nuxeo-browser'); + const isElementVisible = await ele.isVisible(); + if (isElementVisible) { + const resultEle = this.browser.results; + return resultEle; + } + return new Search('nuxeo-search-results-layout[id="results"]'); + })(); } get searchResults() { @@ -71,16 +83,22 @@ export default class UI extends BasePage { } get createDialog() { - this._createDialog = this._createDialog ? this._createDialog : new CreateDialog('#createDocDialog'); - return this._createDialog; + return (async () => { + const createEle = await new CreateDialog('#createDocDialog'); + this._createDialog = this._createDialog ? this._createDialog : createEle; + return this._createDialog; + })(); } get createButton() { - return this.el.element('#createBtn'); + return (async () => { + const buttonCreate = await this.el.element('#createBtn'); + return buttonCreate; + })(); } get adminButton() { - return this.el.element('nuxeo-menu-icon[name="administration"]'); + return this.el.$('nuxeo-menu-icon[name="administration"]'); } get drawer() { @@ -88,17 +106,18 @@ export default class UI extends BasePage { } static get() { - url(process.env.NUXEO_URL ? '' : 'ui'); - if (!global.locale) { - $('nuxeo-app:not([unresolved])').waitForVisible(); - /* global window */ - const locale = browser.execute(() => window.nuxeo.I18n.language || 'en'); - if (locale) { - global.locale = locale; - moment.locale(global.locale); + return (async () => { + url(process.env.NUXEO_URL ? '' : 'ui'); + if (!(await global.locale)) { + await $('nuxeo-app:not([unresolved])').waitForVisible(); + const locale = await browser.execute(async () => (await window.nuxeo.I18n.language) || 'en'); + if (locale) { + global.locale = locale; + await moment.locale(global.locale); + } } - } - return new UI('nuxeo-app'); + return new UI('nuxeo-app'); + })(); } get home() { @@ -110,15 +129,15 @@ export default class UI extends BasePage { } get pages() { - return this.el.element('#pages'); + return this.el.$('#pages'); } get search() { - return this.pages.element('nuxeo-search-results'); + return this.pages.$('nuxeo-search-results'); } get suggester() { - return this.el.element('#mainContainer nuxeo-suggester'); + return this.el.$('#mainContainer nuxeo-suggester'); } get administration() { @@ -126,29 +145,40 @@ export default class UI extends BasePage { } get userCloudServices() { - return new UserCloudServices('nuxeo-user-cloud-services'); + return (async () => { + const cloudServiceELe = await new UserCloudServices('nuxeo-user-cloud-services'); + return cloudServiceELe; + })(); } - goToUserCloudServices() { - if (!browser.getUrl().endsWith('user-cloud-services')) { + async goToUserCloudServices() { + const browserUrl = await browser.getUrl(); + if (!browserUrl.endsWith('user-cloud-services')) { url(process.env.NUXEO_URL ? '#!/user-cloud-services' : 'ui/#!/user-cloud-services'); } - return this.userCloudServices; + + const cloudServiceELe = await this.userCloudServices; + + return cloudServiceELe; + // } } get userAuthorizedApps() { return new UserAuthorizedApps('nuxeo-user-authorized-apps'); } - goToUserAuthorizedApps() { - if (!browser.getUrl().endsWith('user-authorized-apps')) { - url(process.env.NUXEO_URL ? '#!/user-authorized-apps' : 'ui/#!/user-authorized-apps'); + async goToUserAuthorizedApps() { + const browserUrl = await browser.getUrl(); + if (!browserUrl.endsWith('user-authorized-apps')) { + await url(process.env.NUXEO_URL ? '#!/user-authorized-apps' : 'ui/#!/user-authorized-apps'); + } + if (await this.userAuthorizedApps.waitForVisible()) { + return this.userAuthorizedApps; } - return this.userAuthorizedApps; } get tasks() { - return this.pages.element('nuxeo-tasks'); + return this.pages.$('nuxeo-tasks'); } get emptyAuthorizedApps() { @@ -161,7 +191,9 @@ export default class UI extends BasePage { } waitRequests() { - driver.waitUntil(() => !this.isConnectionActive, 5000, 'Waiting for inactive connection'); + driver.waitUntil(() => !this.isConnectionActive, 5000, 'Waiting for inactive connection', { + timeoutMsg: 'waitRequests timeout', + }); } view(option) { @@ -172,22 +204,40 @@ export default class UI extends BasePage { dropdown.click(`#dropdown #contentWrapper div paper-menu div paper-icon-item[name="${selection}"]`); } - waitForToastNotVisible() { - driver.waitUntil(() => driver.elements('mwc-snackbar').every((toast) => !toast.getAttribute('open'))); + async waitForToastNotVisible() { + const mwcsnackbar = await driver.elements('mwc-snackbar'); + let found = true; + for (let i = 0; i < mwcsnackbar.length; i++) { + const toast = await mwcsnackbar[i]; + const isAttrPresent = await toast.getAttribute('open'); + if (isAttrPresent) { + found = false; + break; + } + } + return found; } - getToastDismissButton() { - return this.el.element('#snackbarPanel mwc-snackbar[open] #dismiss'); + async getToastDismissButton() { + const snackbar = await this.el.element('#snackbarPanel mwc-snackbar[open] #dismiss'); + return snackbar; } - getToastMessage(message) { - let snackBar; - driver.waitUntil(() => { - snackBar = this.el.element('#snackbarPanel mwc-snackbar[open] .mdc-snackbar__label'); - const trimmedMessage = message.trim().replace(/"/g, ''); - return snackBar.getText() === trimmedMessage; - }); - return snackBar.getText(); + async getToastMessage(message) { + let snackBarText; + await driver.waitUntil( + async () => { + const snackBar = await this.el.element('#snackbarPanel mwc-snackbar[open] .mdc-snackbar__label'); + snackBarText = await snackBar.getText(); + const trimmedMessage = message.trim().replace(/"/g, ''); + return snackBarText === trimmedMessage; + }, + { + timeoutMsg: 'getToastMessage timedout', + }, + ); + + return snackBarText; } bulkEdit(selector) { @@ -195,6 +245,6 @@ export default class UI extends BasePage { } get filterView() { - return this.el.element('paper-icon-button[id="toogleFilter"]'); + return this.el.$('paper-icon-button[id="toogleFilter"]'); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/activity_feed.js b/packages/nuxeo-web-ui-ftest/pages/ui/activity_feed.js index 63c72635c1..43960ab6a6 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/activity_feed.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/activity_feed.js @@ -1,8 +1,12 @@ import BasePage from '../base'; export default class ActivityFeed extends BasePage { - getActivity(activity) { - this.el.waitForExist('.value span'); - return this.el.$$('.value span').find((e) => e.getText() === activity); + async getActivity(activity) { + await this.el.waitForExist('.value span'); + const valueSpan = await this.el.$$('.value span').find(async (e) => { + const currentText = await e.getText(); + return currentText === activity; + }); + return valueSpan; } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/admin/audit.js b/packages/nuxeo-web-ui-ftest/pages/ui/admin/audit.js index 9848d9852e..38d2c281d7 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/admin/audit.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/admin/audit.js @@ -2,25 +2,39 @@ import BasePage from '../../base'; export default class Audit extends BasePage { get isAuditTableDisplayed() { - return this.el.$('#table').waitForDisplayed(); + return (async () => { + const tableEl = this.el.$('#table').waitForDisplayed(); + return tableEl; + })(); } get isAuditTableFilled() { - this.el.waitForDisplayed('#table nuxeo-data-table-row'); - return !this.el.$$('#table nuxeo-data-table-row').some((row) => row.getText().trim().length === 0); + return (async () => { + const element = await this.el; + const tableRow = await element.$$('#table nuxeo-data-table-row'); + return !( + tableRow.some(async (row) => { + const text = await row.getText(); + return text.trim().length; + }) === 0 + ); + })(); } - waitForHasEntry(action, reverse) { - const { el } = this; - driver.waitUntil( - () => { - const cells = el.$$('#table nuxeo-data-table-cell'); + async waitForHasEntry(action, reverse) { + const el = await this.el; + await driver.waitUntil( + async () => { + const cells = await el.$$('#table nuxeo-data-table-cell'); if (reverse) { - return cells.every((cell) => cell.getText().trim() !== action); + return cells.every(async (cell) => (await cell.getText()).trim() !== action); } - return cells.some((cell) => cell.getText().trim() === action); + return cells.some(async (cell) => (await cell.getText()).trim() === action); }, reverse ? 'The audit does have such entry' : 'The audit does not have such entry', + { + timeoutMsg: 'The audit does have such entry', + }, ); return true; } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/admin/cloudServices.js b/packages/nuxeo-web-ui-ftest/pages/ui/admin/cloudServices.js index ec8dce6492..ba7009a7f1 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/admin/cloudServices.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/admin/cloudServices.js @@ -1,159 +1,173 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../../base'; export default class CloudServices extends BasePage { get nuxeoCloudTokens() { - return this.el.element('nuxeo-cloud-tokens'); + return this.el.$('nuxeo-cloud-tokens'); } get nuxeoCloudTokensAuthorizedApplications() { - return this.el.element('nuxeo-oauth2-provided-tokens'); + return this.el.$('nuxeo-oauth2-provided-tokens'); } get nuxeoCloudTokensCloudAccount() { - return this.el.element('nuxeo-oauth2-consumed-tokens'); + return this.el.$('nuxeo-oauth2-consumed-tokens'); } get nuxeoCloudProviders() { - return this.el.element('nuxeo-cloud-providers'); + return this.el.$('nuxeo-cloud-providers'); } get nuxeoCloudConsumers() { - return this.el.element('nuxeo-cloud-consumers'); - } - - addProvider(provider) { - driver.waitForVisible('#addEntry'); - this.el.element('#addEntry').click(); - driver.waitForVisible('#dialog:not([aria-hidden])'); - this.fillProviderDetails(provider); - this.clickElementName('save'); - } - - editProvider(currentName, newDetails) { - driver.waitForVisible('nuxeo-data-table nuxeo-data-table-row [name="serviceName"]'); - const rows = this.el.elements('nuxeo-data-table nuxeo-data-table-row'); - const edited = rows.some((row) => { - if (row.isVisible('[name="serviceName"]') && row.getText('[name="serviceName"]').trim() === currentName) { - row.click('[name="edit"]'); - driver.waitForVisible('#dialog:not([aria-hidden])'); - this.fillProviderDetails(newDetails); - this.el.click('#dialog:not([aria-hidden]) paper-button[name="save"]'); - return true; - } - return false; - }); - if (!edited) { - throw new Error(`now provider found with named "${currentName}"`); + return this.el.$('nuxeo-cloud-consumers'); + } + + async addProvider(provider) { + await driver.waitForVisible('#addEntry'); + const elem = await this.el.$('#addEntry'); + await elem.click(); + await driver.waitForVisible('#dialog:not([aria-hidden])'); + await this.fillProviderDetails(provider); + await this.clickElementName('save'); + } + + async editProvider(currentName, newDetails) { + const rows = await this.el.$$('nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header])'); + const edited = await this.el + .$$('nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header])') + .map((img) => img.$('nuxeo-data-table-cell span[name="serviceName"]').getText()); + const index = edited.findIndex((currenTitle) => currenTitle === currentName); + if (index !== -1) { + const rowEle = await rows[index]; + const editButton = await rowEle.$('[name="edit"]'); + await editButton.click(); + await driver.waitForVisible('#dialog:not([aria-hidden])'); + await this.fillProviderDetails(newDetails); + const saveButtonEle = await this.el.$('#dialog:not([aria-hidden]) paper-button[name="save"]'); + await saveButtonEle.click(); + return true; } - } - - deleteProvider(serviceName) { - driver.waitForVisible('nuxeo-data-table nuxeo-data-table-row [name="serviceName"]'); - const rows = this.el.elements('nuxeo-data-table nuxeo-data-table-row'); - const deleted = rows.some((row) => { - if (row.isVisible('[name="serviceName"]') && row.getText('[name="serviceName"]').trim() === serviceName) { - row.click('[name="delete"]'); - driver.alertAccept(); - return true; - } - return false; - }); - if (!deleted) { - throw new Error(`now provider found with named "${serviceName}"`); + return false; + } + + async deleteProvider(serviceName) { + const rows = await browser.$$('nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header])'); + const deleted = await browser + .$$('nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header])') + .map((img) => img.$('nuxeo-data-table-cell span[name="serviceName"]').getText()); + const index = deleted.findIndex((currenTitle) => currenTitle === serviceName); + if (index !== -1) { + const rowEle = await rows[index].$('[name="delete"]'); + await rowEle.click(); + await driver.alertAccept(); + return true; } + return false; } - fillProviderDetails(provider) { - provider.rows().forEach((row) => { - this.el.element(`#dialog:not([aria-hidden]) input[name="${row[0]}"`).setValue(row[1]); - }); + async fillProviderDetails(provider) { + const rows = provider.rows(); + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + const abc = await this.el.$(`#dialog:not([aria-hidden]) input[name="${row[0]}"`); + await abc.setValue(row[1]); + } } - clickElementName(name) { + async clickElementName(name) { const selector = `[name="${name}"]`; - driver.waitForVisible(selector); - this.el.element(selector).click(); + await driver.waitForExist(selector); + await this.el.$(selector).click(); } - waitForHasProvider(id, reverse) { - const { el } = this; - driver.waitUntil( - () => { - const providers = el.elements('[name="serviceName"'); + async waitForHasProvider(id, reverse) { + const el = await this.el; + await driver.waitUntil( + async () => { + const providers = await el.elements('[name="serviceName"]'); if (reverse) { - return providers.every((provider) => provider.getText().trim() !== id); + return providers.every(async (provider) => (await provider.getText()).trim() !== id); } - return providers.some((provider) => provider.getText().trim() === id); + return providers.some(async (provider) => (await provider.getText()).trim() === id); }, reverse ? 'The cloud services does have such provider' : 'The cloud services does not have such provider', + { + timeoutMsg: 'waitForHasProvider timedout', + }, ); return true; } - waitForHasClient(id, reverse) { - const { el } = this; - driver.waitUntil( - () => { - const clients = el.elements('[name="id"'); + async waitForHasClient(id, reverse) { + const el = await this.el; + await driver.waitUntil( + async () => { + const clients = await el.elements('[name="id"]'); if (reverse) { - return clients.every((client) => client.getText().trim() !== id); + return clients.every(async (client) => (await client.getText()).trim() !== id); } - return clients.some((client) => client.getText().trim() === id); + return clients.some(async (client) => (await client.getText()).trim() === id); }, reverse ? 'The cloud services does have such client' : 'The cloud services does not have such client', + { + timeoutMsg: 'waitForHasClient timedout', + }, ); return true; } - fillClientDetails(client) { - client.rows().forEach((row) => { - this.el.element(`#dialog:not([aria-hidden]) input[name="${row[0]}"`).setValue(row[1]); - }); - } - - clickOnSaveClientBtn() { - this.el.click('#dialog:not([aria-hidden]) paper-button[id="save"]'); - } - - addClient(client) { - driver.waitForVisible('#addClient'); - this.el.element('#addClient').click(); - driver.waitForVisible('#dialog:not([aria-hidden])'); - this.fillClientDetails(client); - this.clickOnSaveClientBtn(); - } - - editClient(currentClientId, newDetails) { - driver.waitForVisible('nuxeo-data-table nuxeo-data-table-row [name="id"]'); - const rows = this.el.elements('nuxeo-data-table nuxeo-data-table-row'); - const edited = rows.some((row) => { - if (row.isVisible('[name="id"]') && row.getText('[name="id"]').trim() === currentClientId) { - row.click('[name="edit"]'); - driver.waitForVisible('#dialog:not([aria-hidden])'); - this.fillClientDetails(newDetails); - this.clickOnSaveClientBtn(); - return true; - } - return false; - }); - if (!edited) { - throw new Error(`no client found with id "${currentClientId}"`); + async fillClientDetails(client) { + const clientRows = client.rows(); + for (let i = 0; i < clientRows.length; i++) { + const row = clientRows[i]; + const fillClientDetails = await this.el.$(`#dialog:not([aria-hidden]) input[name="${row[0]}"`); + await fillClientDetails.setValue(row[1]); } } - deleteClient(clientId) { - driver.waitForVisible('nuxeo-data-table nuxeo-data-table-row [name="id"]'); - const rows = this.el.elements('nuxeo-data-table nuxeo-data-table-row'); - const deleted = rows.some((row) => { - if (row.isVisible('[name="id"]') && row.getText('[name="id"]').trim() === clientId) { - row.click('[name="delete"]'); - driver.alertAccept(); - return true; - } - return false; - }); - if (!deleted) { - throw new Error(`no client found with Id "${clientId}"`); + async clickOnSaveClientBtn() { + const saveButton = await this.el.element('#dialog:not([aria-hidden]) paper-button[id="save"]'); + await saveButton.click(); + } + + async addClient(client) { + await driver.waitForVisible('#addClient'); + const addClient = await this.el.element('#addClient'); + await addClient.click(); + await driver.waitForVisible('#dialog:not([aria-hidden])'); + await this.fillClientDetails(client); + await this.clickOnSaveClientBtn(); + } + + async editClient(currentClientId, newDetails) { + const rows = await this.el.$$('nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header])'); + const edited = await this.el + .$$('nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header])') + .map((img) => img.$('nuxeo-data-table-cell span[name="id"]').getText()); + const index = edited.findIndex((currenTitle) => currenTitle === currentClientId); + if (index !== -1) { + const rowEle = await rows[index].$('[name="edit"]'); + await rowEle.click(); + await driver.waitForVisible('#dialog:not([aria-hidden])'); + await this.fillClientDetails(newDetails); + await this.clickOnSaveClientBtn(); + return true; + } + return false; + } + + async deleteClient(clientId) { + const rows = await browser.$$('nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header])'); + const deleted = await browser + .$$('nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header])') + .map((img) => img.$('nuxeo-data-table-cell span[name="id"]').getText()); + const index = deleted.findIndex((currenTitle) => currenTitle === clientId); + if (index !== -1) { + const rowEle = await rows[index].$('[name="delete"]'); + await rowEle.click(); + await driver.alertAccept(); + return true; } + return false; } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/admin/vocabulary.js b/packages/nuxeo-web-ui-ftest/pages/ui/admin/vocabulary.js index 1a3c4dbd3b..c68bf35d92 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/admin/vocabulary.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/admin/vocabulary.js @@ -1,107 +1,147 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../../base'; export default class Vocabulary extends BasePage { - vocabulary(option) { - const selection = option.toLowerCase(); - const dropdown = this.el.element('#menuButton'); - dropdown.waitForVisible(); - dropdown.click(); - const item = this.el.element(`nuxeo-select paper-item[name="${selection}"]`); - item.waitForVisible(); - item.click(); + async vocabulary(option) { + const selection = await option.toLowerCase(); + const dropdown = await this.el.element('#menuButton'); + await dropdown.waitForVisible(); + await dropdown.click(); + const item = await this.el.element(`nuxeo-select paper-item[name="${selection}"]`); + await item.waitForVisible(); + await item.click(); } - addNewEntry(id, label) { - driver.waitForVisible('#addEntry'); - this.el.element('#addEntry').click(); - const dialog = this.el.element('nuxeo-dialog[id="vocabularyEditDialog"]:not([aria-hidden])'); - dialog.waitForVisible(); - dialog.waitForVisible('input[name="id"]'); - dialog.element('input[name="id"]').setValue(id); - dialog.waitForVisible('input[name="label"]'); - dialog.element('input[name="label"]').setValue(label); - dialog.waitForVisible('paper-button[name="save"]'); - dialog.click('paper-button[name="save"]'); + async addNewEntry(id, label) { + await driver.waitForVisible('#addEntry'); + const addEntryButton = await this.el.element('#addEntry'); + await addEntryButton.click(); + const dialog = await this.el.element('nuxeo-dialog[id="vocabularyEditDialog"]:not([aria-hidden])'); + await dialog.waitForVisible(); + const idInput = await dialog.element('input[name="id"]'); + await idInput.setValue(id); + const labelInput = await dialog.element('input[name="label"]'); + await labelInput.setValue(label); + const saveButton = await dialog.element('paper-button[name="save"]'); + await saveButton.waitForVisible(); + await saveButton.click(); } - waitForHasEntry(id, reverse) { - const { el } = this; - driver.waitForVisible('#table'); - driver.waitUntil( - () => { - const cells = el.elements('#table nuxeo-data-table-cell'); + async waitForHasEntry(id, reverse) { + const el = await this.el; + await driver.waitForVisible('#table'); + await driver.waitUntil( + async () => { + const cells = await el.elements('#table nuxeo-data-table-cell'); if (reverse) { - return cells.every((cell) => cell.getText().trim() !== id); + return cells.every(async (cell) => (await cell.getText()).trim() !== id); } - return cells.some((cell) => cell.getText().trim() === id); + return cells.some(async (cell) => (await cell.getText()).trim() === id); }, reverse ? 'The vocabulary does have such entry' : 'The vocabulary does not have such entry', + { + timeoutMsg: 'waitForHasEntry timedout', + }, ); return true; } - deleteEntry(index) { + async deleteEntry(index) { const selector = `#delete-button-${index - 1}`; - this.el.element(selector).click(); - driver.alertAccept(); + const deleteButton = await this.el.element(selector); + await deleteButton.scrollIntoView(selector); + await deleteButton.click(); + await driver.alertAccept(); } - editEntry(index, label) { + async editEntry(index, label) { const selector = `#edit-button-${index - 1}`; - this.el.element(selector).click(); - const dialog = this.el.element('nuxeo-dialog[id="vocabularyEditDialog"]:not([aria-hidden])'); - dialog.waitForVisible(); - dialog.waitForVisible('input[name="label"]'); - dialog.element('input[name="label"]').setValue(label); - dialog.click('paper-button[name="save"]'); + const editButton = await this.el.element(selector); + await editButton.scrollIntoView(selector); + await editButton.click(); + const dialog = await this.el.element('nuxeo-dialog[id="vocabularyEditDialog"]:not([aria-hidden])'); + await dialog.waitForVisible(); + await dialog.waitForVisible('input[name="label"]'); + const labelInput = await dialog.element('input[name="label"]'); + await labelInput.setValue(label); + const saveButton = await dialog.element('paper-button[name="save"]'); + await saveButton.click(); } get isVocabularyTableVisible() { - return this.el.element('#table').waitForVisible(); + return (async () => { + const table = await this.el.element('#table'); + return table.waitForVisible(); + })(); } get entryCount() { - const res = this.el.elements('#table #items nuxeo-data-table-row'); - if (res) { - return res.length; - } - return 0; + return async () => { + const res = await this.el.elements('#table #items nuxeo-data-table-row'); + if (res) { + return res.length; + } + return 0; + }; } - table() { - driver.waitForVisible('#table'); + async table() { + await driver.waitForVisible('#table'); return this.el.element('#table'); } get isVocabularyTableFilled() { - this.el.waitForVisible('#table nuxeo-data-table-row'); - return !this.el.elements('#table nuxeo-data-table-row').some((row) => row.getText().trim().length === 0); + return (async () => { + const tableRow = await this.el.element('#table nuxeo-data-table-row'); + await tableRow.waitForVisible(); + const rows = await this.el.elements('#table nuxeo-data-table-row'); + const isTableNotEmpty = await rows.every(async (row) => (await row.getText()).trim().length !== 0); + return isTableNotEmpty; + })(); } get hasEditDialog() { - driver.waitForVisible('#edit-button-0'); - this.el.element('#edit-button-0').click(); - this.el.waitForVisible('nuxeo-dialog[id="vocabularyEditDialog"]:not([aria-hidden])'); - const dialog = this.el.element('nuxeo-dialog[id="vocabularyEditDialog"]:not([aria-hidden])'); - const allFieldVisible = dialog.waitForVisible('input[name="label"]') && dialog.waitForVisible('input[name="id"]'); - dialog.waitForVisible('paper-button[name="cancel"]'); - dialog.element('paper-button[name="cancel"]').click(); - return allFieldVisible; + return async () => { + await driver.waitForVisible('#edit-button-0'); + const editButton = await this.el.element('#edit-button-0'); + await editButton.click(); + await this.el.waitForVisible('nuxeo-dialog[id="vocabularyEditDialog"]:not([aria-hidden])'); + const dialog = await this.el.element('nuxeo-dialog[id="vocabularyEditDialog"]:not([aria-hidden])'); + const labelFieldVisible = await dialog.element('input[name="label"]'); + const labelFieldVisibleValue = await labelFieldVisible.waitForVisible(); + const idFieldVisible = await dialog.element('input[name="id"]'); + const idFieldVisibleValue = await idFieldVisible.waitForVisible(); + const allFieldVisible = labelFieldVisibleValue && idFieldVisibleValue; + await dialog.waitForVisible('paper-button[name="cancel"]'); + const cancelButton = await dialog.element('paper-button[name="cancel"]'); + await cancelButton.click(); + return allFieldVisible; + }; } get hasCreateDialog() { - this.el.waitForVisible('#addEntry'); - this.el.element('#addEntry').click(); - this.el.waitForVisible('nuxeo-dialog[id="vocabularyEditDialog"]:not([aria-hidden])'); - const dialog = this.el.element('nuxeo-dialog[id="vocabularyEditDialog"]:not([aria-hidden])'); - const allFieldVisible = dialog.waitForVisible('input[name="label"]') && dialog.waitForVisible('input[name="id"]'); - dialog.element('#selectParent').click(); - dialog.waitForVisible('#parentDialog nuxeo-tree-node:first-child'); - dialog.waitForVisible('#parentDialog paper-button[name="close"]'); - dialog.element('#parentDialog paper-button[name="close"]').click(); - dialog.waitForVisible('paper-button[name="cancel"]'); - dialog.scrollIntoView('paper-button[name="cancel"]'); - dialog.element('paper-button[name="cancel"]').click(); - return allFieldVisible; + return async () => { + await this.el.waitForVisible('#addEntry'); + const addButton = await this.el.element('#addEntry'); + await addButton.click(); + await this.el.waitForVisible('nuxeo-dialog[id="vocabularyEditDialog"]:not([aria-hidden])'); + const dialog = await this.el.element('nuxeo-dialog[id="vocabularyEditDialog"]:not([aria-hidden])'); + const labelFieldVisible = await dialog.element('input[name="label"]'); + const labelFieldVisibleValue = await labelFieldVisible.waitForVisible(); + const idFieldVisible = await dialog.element('input[name="id"]'); + const idFieldVisibleValue = await idFieldVisible.waitForVisible(); + const allFieldVisible = labelFieldVisibleValue && idFieldVisibleValue; + const selectParent = await dialog.element('#selectParent'); + await selectParent.click(); + await dialog.waitForVisible('#parentDialog nuxeo-tree-node:first-child'); + await dialog.waitForVisible('#parentDialog paper-button[name="close"]'); + const parentDialog = await dialog.element('#parentDialog paper-button[name="close"]'); + await parentDialog.click(); + await dialog.waitForVisible('paper-button[name="cancel"]'); + await dialog.scrollIntoView('paper-button[name="cancel"]'); + const cancel = await dialog.element('paper-button[name="cancel"]'); + await cancel.click(); + return allFieldVisible; + }; } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/administration.js b/packages/nuxeo-web-ui-ftest/pages/ui/administration.js index 6c48461731..19b888a80a 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/administration.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/administration.js @@ -18,19 +18,26 @@ export default class Administration extends BasePage { } get userGroupCreateButton() { - return this.el.element('#createButton'); + return (async () => { + const createEle = await this.el.element('#createButton'); + return createEle; + })(); } get vocabularyManagement() { - if (!browser.getUrl().endsWith('vocabulary-management')) { - url(process.env.NUXEO_URL ? '#!/admin/vocabulary-management' : 'ui/#!/admin/vocabulary-management'); - } - return new Vocabulary('nuxeo-vocabulary-management'); - } - - goToVocabularyManagement() { - if (!browser.getUrl().endsWith('vocabulary-management')) { - url(process.env.NUXEO_URL ? '#!/admin/vocabulary-management' : 'ui/#!/admin/vocabulary-management'); + return (async () => { + const browserUrl = await browser.getUrl(); + if (!browserUrl.endsWith('vocabulary-management')) { + await url(process.env.NUXEO_URL ? '#!/admin/vocabulary-management' : 'ui/#!/admin/vocabulary-management'); + } + return new Vocabulary('nuxeo-vocabulary-management'); + })(); + } + + async goToVocabularyManagement() { + const browserUrl = await browser.getUrl(); + if (!browserUrl.endsWith('vocabulary-management')) { + await url(process.env.NUXEO_URL ? '#!/admin/vocabulary-management' : 'ui/#!/admin/vocabulary-management'); } return this.vocabularyManagement; } @@ -43,9 +50,11 @@ export default class Administration extends BasePage { return new CloudServices('nuxeo-cloud-services'); } - goToCloudServices() { - if (!browser.getUrl().endsWith('cloud-services')) { - url(process.env.NUXEO_URL ? '#!/admin/cloud-services' : 'ui/#!/admin/cloud-services'); + async goToCloudServices() { + const browserUrl = await browser.getUrl(); + await driver.pause(1000); + if (!browserUrl.endsWith('cloud-services')) { + await url(process.env.NUXEO_URL ? '#!/admin/cloud-services' : 'ui/#!/admin/cloud-services'); } return this.cloudServices; } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser.js index 3909d41c3e..2164aa4a21 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser.js @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../base'; import DocumentPage from './browser/document_page'; import CollapsibleDocumentPage from './browser/collapsible_document_page'; @@ -12,19 +13,21 @@ import Results from './results'; import { clickActionMenu, url } from '../helpers'; export default class Browser extends BasePage { - documentPage(docType) { - const page = fixtures.layouts.page[docType] || 'nuxeo-document-page'; + async documentPage(docType) { + const page = (await fixtures.layouts.page[docType]) || 'nuxeo-document-page'; if (page === 'nuxeo-collapsible-document-page') { return new CollapsibleDocumentPage(page, docType); } return new DocumentPage(page, docType); } - browseTo(path) { - url(`#!/browse${path}`); - this.waitForVisible(); - this.breadcrumb.waitForVisible(); - this.currentPage.waitForVisible(); + async browseTo(path) { + await url(`#!/browse${path}`); + await this.waitForVisible(); + const breadcrumb = await this.breadcrumb; + await breadcrumb.waitForVisible(); + const currentPage = await this.currentPage; + await currentPage.waitForVisible(); } get view() { @@ -40,7 +43,7 @@ export default class Browser extends BasePage { } get permissionsViewButton() { - return this.el.element('nuxeo-page-item[name="permissions"]'); + return this.el.$('nuxeo-page-item[name="permissions"]'); } get publicationView() { @@ -48,7 +51,7 @@ export default class Browser extends BasePage { } get publicationViewButton() { - return this.el.element('nuxeo-page-item[name="publication"]'); + return this.el.$('nuxeo-page-item[name="publication"]'); } get documentTaskView() { @@ -56,260 +59,363 @@ export default class Browser extends BasePage { } get currentPageName() { - // get selected pill to get it's name - this.waitForVisible('#documentViewsItems nuxeo-page-item.iron-selected'); - const pill = this.el.element('#documentViewsItems nuxeo-page-item.iron-selected'); - // get active page name - return pill.getAttribute('name'); + return (async () => { + // get selected pill to get it's name + const pill = await this.el.element('#documentViewsItems nuxeo-page-item.iron-selected'); + const attributeName = await pill.getAttribute('name'); + return attributeName; + })(); } get currentPage() { - return this._section(this.currentPageName); + return (async () => { + const pageName = await this.currentPageName; + const section = await this._section(pageName); + return section; + })(); } /** * Gets a Results page helper, assuming current visible page has a in there. */ get results() { - const pill = this.el.element('#documentViewsItems nuxeo-page-item.iron-selected'); - return new Results(`#nxContent [name='${pill.getAttribute('name')}']`); + return (async () => { + const ele = await this.el; + const pill = await ele.$('#documentViewsItems nuxeo-page-item.iron-selected'); + const getAttributeName = await pill.getAttribute('name'); + const getViewElement = await new Results(`#nxContent [name=${getAttributeName}]`); + return getViewElement; + })(); } get breadcrumb() { - return this.el.element('nuxeo-breadcrumb'); + return (async () => { + const element = await this.el.element('nuxeo-breadcrumb'); + return element; + })(); } get title() { return this.breadcrumb.getText('.breadcrumb-item-current'); } - _section(name) { - return this.el.element(`#nxContent [name='${name}']`); + async _section(name) { + const nxname = await this.el.$(`#nxContent [name='${name}']`); + return nxname; } get editButton() { - return this.el.element('#edit-button'); + return (async () => { + const editButton = await this.el.$('#edit-button'); + return editButton; + })(); } - editForm(docType) { - return new DocumentFormLayout('#edit-dialog nuxeo-document-form-layout', docType, 'edit'); + async editForm(docType) { + const docFormLayout = await new DocumentFormLayout('#edit-dialog nuxeo-document-form-layout', docType, 'edit'); + return docFormLayout; } get header() { - return this.currentPage.element('nuxeo-data-table[name="table"] nuxeo-data-table-row[header]'); + return (async () => { + const currentPage = await this.currentPage; + const ele = await currentPage.$('nuxeo-data-table[name="table"] nuxeo-data-table-row[header]'); + return ele; + })(); } get rows() { - return this.currentPage.elements('nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header])'); - } - - waitForChildren() { - this.currentPage.waitForExist('nuxeo-data-table[name="table"] nuxeo-data-table-row nuxeo-data-table-checkbox'); - } - - addToCollection(name) { - const button = this.el.element('nuxeo-add-to-collection-button'); - button.waitForVisible(); - if (!button.isExisting('#dialog') || !button.isVisible('#dialog')) { - button.click(); + return (async () => { + const currentPage = await this.currentPage; + let rowsTemp; + await driver.waitUntil( + async () => { + rowsTemp = await currentPage.elements('nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header])'); + return rowsTemp.length > 0; + }, + { + timeout: 10000, + timeoutMsg: 'rows not found!!', + }, + ); + return rowsTemp; + })(); + } + + async waitForChildren() { + const currentPage = await this.currentPage; + const ele = await currentPage.$('nuxeo-data-table[name="table"] nuxeo-data-table-row nuxeo-data-table-checkbox'); + await ele.waitForExist(); + } + + async addToCollection(name) { + const button = await this.el.$('nuxeo-add-to-collection-button'); + await button.waitForVisible(); + const dialogExistingEle = await button.isExisting('#dialog'); + const dialogVisibleEle = await button.isVisible('#dialog'); + if (!dialogExistingEle || !dialogVisibleEle) { + await button.click(); } - const dialog = new AddToCollectionDialog(`${this._selector} nuxeo-add-to-collection-button #dialog`); - dialog.waitForVisible(); - dialog.addToCollection(name); - this.el.waitForVisible('nuxeo-document-collections nuxeo-tag'); + const dialog = await new AddToCollectionDialog(`${this._selector} nuxeo-add-to-collection-button #dialog`); + await dialog.waitForVisible(); + await dialog.addToCollection(name); + const docCollectionEle = await this.el.$('nuxeo-document-collections nuxeo-tag'); + await docCollectionEle.waitForVisible(); } - doesNotHaveCollection(name) { + async doesNotHaveCollection(name) { const page = this.el; - driver.waitUntil(() => { - if (!driver.isExisting('nuxeo-document-collections')) { - return true; - } - try { - const collections = page.elements('nuxeo-document-collections nuxeo-tag'); - return collections.every((collection) => collection.getText().trim() !== name); - } catch (e) { - return false; + const nuxeoDocEle = await driver.isExisting('nuxeo-document-collections'); + if (!nuxeoDocEle) { + return true; + } + try { + const collections = await page.elements('nuxeo-document-collections nuxeo-tag'); + for (let i = 0; i < collections.length; i++) { + const collection = await collections[i]; + const getTextEle = await collection.getText(); + if (getTextEle.trim() !== name) { + return false; + } } - }, 'The document does belong to the collection'); - return true; + return true; + } catch (e) { + return false; + } } - hasCollection(name) { - const page = this.el; - driver.waitUntil(() => { - if (!driver.isExisting('nuxeo-document-collections')) { - return false; - } - try { - const collections = page.elements('nuxeo-document-collections nuxeo-tag a'); - return collections.some((collection) => collection.getText().trim() === name); - } catch (e) { - return false; + async hasCollection(name) { + const page = await this.el; + const docCollection = await driver.isExisting('nuxeo-document-collections'); + if (!docCollection) { + return false; + } + try { + const collections = await page.$$('nuxeo-document-collections nuxeo-tag a'); + for (let i = 0; i < collections.length; i++) { + const collection = await collections[i]; + const getTextEle = await collection.getText(); + if (getTextEle.trim() === name) { + return true; + } } - }, 'The document does not belong to the collection'); - return true; + return false; + } catch (e) { + return false; + } } - removeFromCollection(name) { - const { el } = this; - el.waitForVisible('nuxeo-document-collections nuxeo-tag'); - const collections = this.el.elements('nuxeo-document-collections nuxeo-tag'); - collections.some((collection) => { - if (collection.getText().trim() === name) { - const remove = collection.element('iron-icon[name="remove"]'); - remove.waitForVisible(); - remove.scrollIntoView(); - remove.click(); - return true; + async removeFromCollection(name) { + const { el } = await this; + await el.$('nuxeo-document-collections nuxeo-tag').waitForVisible(); + const collections = await this.el.$$('nuxeo-document-collections nuxeo-tag'); + let found = false; + for (let index = 0; index < collections.length; index++) { + const collectionText = await collections[index].getText(); + if (collectionText.trim() === name) { + const remove = await collections[index].$('iron-icon[name="remove"]'); + await remove.waitForVisible(); + await remove.scrollIntoView(); + await remove.click(); + found = true; } return false; - }); + } + return found; } - removeSelectionFromCollection() { - const button = this.el.element('nuxeo-collection-remove-action'); - button.waitForVisible(); - button.click(); + async removeSelectionFromCollection() { + const button = await this.el.$('nuxeo-collection-remove-action'); + await button.waitForVisible(); + await button.click(); } get isFavorite() { - this.el.waitForExist('nuxeo-favorites-toggle-button[favorite]'); - return true; + return (async () => { + await this.el.waitForExist('nuxeo-favorites-toggle-button[favorite]'); + return true; + })(); } - addToFavorites() { - this.el.click('nuxeo-favorites-toggle-button'); - return this.isFavorite; + async addToFavorites() { + await this.el.$('nuxeo-favorites-toggle-button').click(); + const fav = await this.isFavorite; + return fav; } - hasTitle(title) { - $('.breadcrumb-item-current').waitForVisible(); - driver.waitUntil( - () => - $('.breadcrumb-item-current') - .getText() - .trim() === title, - 'The document does not have such title', - ); - return true; + async hasTitle(title) { + await driver.pause(1000); + const breadcrumb = await $('.breadcrumb-item-current'); + const breadcrumbText = await breadcrumb.getText(); + if (breadcrumbText.trim() === title) { + return true; + } + return false; } - waitForHasChild(doc) { + async waitForHasChild(doc) { const { el } = this; - el.waitForVisible('nuxeo-data-table[name="table"] nuxeo-data-table-row a.title'); - const titles = el.elements('nuxeo-data-table[name="table"] nuxeo-data-table-row a.title'); - return titles.some((title) => title.getText().trim() === doc.title); - } - - clickChild(title) { - this.waitForChildren(); - return this.rows.some((row) => { - if ( - row.isVisible('nuxeo-data-table-cell a.title') && - row.getText('nuxeo-data-table-cell a.title').trim() === title - ) { - row.click(); + const dataTable = await el.$('nuxeo-data-table[name="table"] nuxeo-data-table-row a.title'); + await dataTable.waitForVisible(); + const titles = await el.$$('nuxeo-data-table[name="table"] nuxeo-data-table-row a.title'); + for (let i = 0; i < titles.length; i++) { + const row = await titles[i].getText(); + if (row.trim() === doc.title) { return true; } - return false; - }); + } + return false; + } + + async clickChild(title) { + await this.waitForChildren(); + const rowTemp = await this.rows; + for (let i = 0; i < rowTemp.length; i++) { + const row = rowTemp[i]; + const rowEl = await row.$('nuxeo-data-table-cell a.title'); + const rowVisible = await rowEl.isVisible(); + const getText = await rowEl.getText(); + const rowText = (await getText.trim()) === title; + if (rowVisible && rowText) { + await row.click(); + return true; // Exit the loop once a match is found + } + } + return false; } - indexOfChild(title) { - this.waitForChildren(); - const { rows } = this; - let i; - for (i = 0; i < rows.length; i++) { - if ( - rows[i] - .element('nuxeo-data-table-cell a.title') - .getText() - .trim() === title - ) { + async indexOfChild(title) { + await this.waitForChildren(); + const elementTitle = await browser + .$$('nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header])') + .map(async (img) => img.$('nuxeo-data-table-cell a.title').getText()); + + for (let i = 0; i < elementTitle.length; i++) { + if ((await elementTitle[i].trim()) === title) { return i; } } return -1; } - sortContent(field, order) { - driver.waitUntil(() => { - this.waitForChildren(); - const columns = this.currentPage.elements('nuxeo-data-table[name="table"] nuxeo-data-table-column'); - const idx = columns - .map((col) => browser.execute((el) => el.sortBy, col)) - .findIndex((colSortByField) => colSortByField && colSortByField.toLowerCase() === field.toLowerCase()); - if (idx === -1) { + async sortContent(field, order) { + try { + await this.waitForChildren(); + const currentPage = await this.currentPage; + const idx = await currentPage + .$$('nuxeo-data-table[name="table"] nuxeo-data-table-column') + .map((col) => browser.execute((el) => el.sortBy, col)); + const columnIndex = idx.findIndex((colSortByField) => { + const sortByColumn = colSortByField; + return sortByColumn && sortByColumn.toLowerCase() === field.toLowerCase(); + }); + if (columnIndex === -1) { throw new Error('Field not found'); } - const header = this.currentPage.element('nuxeo-data-table[name="table"] nuxeo-data-table-row[header]'); - const sortElt = header.element(`nuxeo-data-table-cell:nth-of-type(${idx + 1}) nuxeo-data-table-column-sort`); - const currentSorting = sortElt.element('paper-icon-button').getAttribute('direction'); - if (currentSorting && order.toLowerCase() === currentSorting.toLowerCase()) { + const header = await currentPage.element('nuxeo-data-table[name="table"] nuxeo-data-table-row[header]'); + const sortElt = await header.$( + `nuxeo-data-table-cell:nth-of-type(${columnIndex + 1}) nuxeo-data-table-column-sort`, + ); + const currentSorting = await sortElt.element('paper-icon-button'); + const direction = await currentSorting.getAttribute('direction'); + if (direction && order.toLowerCase() === direction.toLowerCase()) { return true; } - sortElt.click(); + await sortElt.click(); return false; - }); + } catch (error) { + console.warn(error); + } } /* * Results might vary with the viewport size as only visible items are taken into account. */ - waitForNbChildren(nb) { - driver.waitUntil(() => { - let count = 0; + async waitForNbChildren(nb) { + let count; + await driver.waitUntil(async () => { + const currentPage = await this.currentPage; + const rowTemp = await currentPage.$$('nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header])'); + count = 0; try { - const { rows } = this; - rows.forEach((row) => { - if (row.isVisible() && row.isVisible('nuxeo-data-table-cell a.title')) { + for (let i = 0; i < rowTemp.length; i++) { + const row = await rowTemp[i]; + if ((await row.isVisible()) && (await row.isVisible('nuxeo-data-table-cell a.title'))) { count++; } - }); + } return count === nb; } catch (e) { // prevent stale row from breaking execution return false; } }); - } - - selectAllChildDocuments() { - this.waitForChildren(); - this.rows.forEach((row) => { - if (row.isVisible('nuxeo-data-table-checkbox')) { - row.element('nuxeo-data-table-checkbox').click(); + return count; + } + + async selectAllChildDocuments() { + await this.waitForChildren(); + await driver.waitUntil( + async () => { + const rowWithCheckbox = await browser.$$( + 'nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header] nuxeo-data-table-checkbox', + ); + return rowWithCheckbox.length > 0; + }, + { + timeout: 10000, + timeoutMsg: 'expecteed selectAllChildDocuments', + }, + ); + const rowTemp = await this.rows; + for (let index = 0; index < rowTemp.length; index++) { + const checkboxVisible = await rowTemp[index].isVisible('nuxeo-data-table-checkbox'); + if (checkboxVisible) { + rowTemp[index].$('nuxeo-data-table-checkbox').click(); } - }); + } } - selectAllDocuments() { - this.waitForChildren(); - const { header } = this; - if (header.isVisible('nuxeo-data-table-checkbox')) { - header.element('nuxeo-data-table-checkbox').click(); + async selectAllDocuments() { + await this.waitForChildren(); + const currentPage = await this.currentPage; + const header = await currentPage.$('nuxeo-data-table[name="table"] nuxeo-data-table-row[header]'); + const ele = await header.$('nuxeo-data-table-checkbox'); + const isHeaderVisible = await ele.isVisible(); + if (await isHeaderVisible) { + await ele.click(); } } - selectChildDocument(title) { - return this._selectChildDocument(title); + async selectChildDocument(title) { + const childDoc = await this._selectChildDocument(title); + return childDoc; } - deselectChildDocument(title) { - return this._selectChildDocument(title, true); + async deselectChildDocument(title) { + const childDoc = await this._selectChildDocument(title, true); + return childDoc; } get publicationInfobar() { - return this.el.element('nuxeo-publication-info-bar'); + return (async () => { + const ele = await this.el; + const outElement = await ele.$('nuxeo-publication-info-bar'); + return outElement; + })(); } get selectionToolbar() { - return new Selection(`${this.currentPage.getTagName()} nuxeo-selection-toolbar#toolbar`); + return (async () => { + const currentPage = await this.currentPage; + const tagName = await currentPage.getTagName(); + const selectionBar = await new Selection(`${tagName} nuxeo-selection-toolbar#toolbar`); + return selectionBar; + })(); } get trashedInfobar() { - return this.el.element('#trashedInfoBar'); + return this.el.$('#trashedInfoBar'); } get trashDocumentButton() { @@ -329,50 +435,57 @@ export default class Browser extends BasePage { get startWorkflowButton() { // XXX: using a more specific selector here to ensure we can check for isExisting() - return this.el.element('.document-actions nuxeo-workflow-button #startButton'); + return this.el.$('.document-actions nuxeo-workflow-button #startButton'); } - clickDocumentActionMenu(selector) { - clickActionMenu(this.el.element('nuxeo-actions-menu'), selector); + async clickDocumentActionMenu(selector) { + const ele = await this.el; + const id = await ele.$('nuxeo-actions-menu'); + await clickActionMenu(id, selector); } - startWorkflow(workflow) { + async startWorkflow(workflow) { // click the action to trigger the dialog - clickActionMenu(this.el, 'nuxeo-workflow-button'); + await clickActionMenu(this.el, 'nuxeo-workflow-button'); // select the workflow - const workflowSelect = this.el.element('.document-actions nuxeo-workflow-button nuxeo-select'); - workflowSelect.waitForVisible(); - fixtures.layouts.setValue(workflowSelect, workflow); + const workflowSelect = await this.el.$('.document-actions nuxeo-workflow-button nuxeo-select'); + await workflowSelect.waitForVisible(); + await fixtures.layouts.setValue(workflowSelect, workflow); // click the start button - this.el.element('.document-actions nuxeo-workflow-button #startButton').click(); - } - - _selectChildDocument(title, deselect) { - const found = this.rows.some((row) => { - if ( - (deselect - ? row.isVisible('nuxeo-data-table-checkbox[checked]') - : row.isVisible('nuxeo-data-table-checkbox:not([checked])')) && - row.getText('nuxeo-data-table-cell a.title').trim() === title - ) { - row.element('nuxeo-data-table-checkbox').click(); - return true; - } - return false; - }); - if (!found) { - throw new Error(`Cannot find document with title "${title}"`); + const ele = await this.el.$('.document-actions nuxeo-workflow-button #startButton'); + await ele.click(); + } + + async _selectChildDocument(title, deselect) { + const rowTemp = await this.rows; + const elementTitle = await browser + .$$('nuxeo-data-table[name="table"] nuxeo-data-table-row:not([header])') + .map((img) => img.$('nuxeo-data-table-cell a.title').getText()); + const nonEmptyTitles = elementTitle.filter((nonEmpty) => nonEmpty.trim() !== ''); + const index = nonEmptyTitles.findIndex((currenTitle) => currenTitle === title); + await driver.pause(3000); + const isCheckedVisible = await rowTemp[index].isVisible('nuxeo-data-table-checkbox[checked]'); + await driver.pause(1000); + const isNotCheckedVisible = await rowTemp[index].isVisible('nuxeo-data-table-checkbox:not([checked])'); + if ((deselect ? isCheckedVisible : isNotCheckedVisible) && index >= 0) { + const currentRow = await rowTemp[index].$('nuxeo-data-table-checkbox'); + await currentRow.click(); + return true; } + return false; } get publishDialog() { - clickActionMenu(this.el, 'nuxeo-publish-button'); - const publishDialog = new PublicationDialog('#publishDialog'); - publishDialog.waitForVisible(); - return publishDialog; + return (async () => { + const ele = await this.el; + await clickActionMenu(ele, 'nuxeo-publish-button'); + const publishDialog = new PublicationDialog('#publishDialog'); + await publishDialog.waitForVisible(); + return publishDialog; + })(); } get comparePage() { - return this.el.element('nuxeo-diff-page div.header'); + return this.el.$('nuxeo-diff-page div.header'); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser/add_to_collection_dialog.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser/add_to_collection_dialog.js index c6d540aebd..03805529c9 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser/add_to_collection_dialog.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser/add_to_collection_dialog.js @@ -1,12 +1,13 @@ import BasePage from '../../base'; export default class AddToCollectionDialog extends BasePage { - addToCollection(collectionName) { - const collectionSelect = this.el.element('#nxSelect'); - collectionSelect.waitForVisible(); - fixtures.layouts.setValue(collectionSelect, collectionName); - this.el.waitForEnabled('paper-button[name="add"]'); - this.el.click('paper-button[name = "add"]'); + async addToCollection(collectionName) { + const collectionSelect = await this.el.$('#nxSelect'); + await collectionSelect.waitForVisible(); + await fixtures.layouts.setValue(collectionSelect, collectionName); + await this.el.waitForEnabled('paper-button[name="add"]'); + const addCollection = await this.el.$('paper-button[name = "add"]'); + await addCollection.click(); } waitForVisible() { diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser/collapsible_document_page.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser/collapsible_document_page.js index 3694a7b29a..e7c49a3fd4 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser/collapsible_document_page.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser/collapsible_document_page.js @@ -20,12 +20,13 @@ export default class CollapsibleDocumentPage extends DocumentPage { return super.versions; } - expandDetailsCard() { - this.detailsCard.waitForVisible(); + async expandDetailsCard() { + const detailcardEle = await this.detailsCard; + await detailcardEle.waitForVisible(); // XXX: getAttribute('opened') returns 'false' instead of null when the attribute is set to false, not sure why - if (this.detailsCard.getAttribute('opened') === 'false') { - this.detailsCard.waitForVisible('h5.header'); - this.detailsCard.click('h5.header'); + if (detailcardEle.getAttribute('opened') === 'false') { + await detailcardEle.waitForVisible('h5.header'); + await detailcardEle.click('h5.header'); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_comment.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_comment.js index 2b7915569f..aff36429c9 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_comment.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_comment.js @@ -6,52 +6,81 @@ export default class DocumentComment { } get author() { - return this._el.element('.author'); + return (async () => { + const author = await this._el.element('.author'); + return author; + })(); } get dialog() { - return this._el.element('#dialog'); + return (async () => { + const dialog = this._el.element('#dialog'); + return dialog; + })(); } get options() { - return this._el.$('.horizontal #options'); + return (async () => { + const horizontalOption = await this._el.$('.horizontal #options'); + return horizontalOption; + })(); } get replyButton() { - return this._el.element('.text iron-icon[name="reply"]'); + return (async () => { + const replyButton = await this._el.element('.text iron-icon[name="reply"]'); + return replyButton; + })(); } get summaryLink() { - return this._el.element('#summary .more-content'); + return (async () => { + const summaryLinkContent = await this._el.element('#summary .more-content'); + return summaryLinkContent; + })(); } get text() { - return this._el.element('.text span'); + return (async () => { + const text = await this._el.element('.text span'); + return text; + })(); } get thread() { - return new DocumentCommentThread('#thread'); + return (async () => { + const docThread = await new DocumentCommentThread('#thread'); + return docThread; + })(); } - edit() { - this.options.scrollIntoView(); - this.options.click(); - this.options.element('paper-icon-item[name="edit"]').click(); + async edit() { + const options = await this.options; + await options.scrollIntoView(); + await options.click(); + const editButton = await options.element('paper-icon-item[name="edit"]'); + await editButton.click(); } - remove() { - this.options.scrollIntoView(); - this.options.click(); - this.options.element('paper-icon-item[name="delete"]').click(); - this.dialog.waitForVisible(); - this.dialog.element('paper-button[name="confirm"]').click(); + async remove() { + const options = await this.options; + const dialog = await this.dialog; + await options.scrollIntoView(); + await options.click(); + const deleteButton = await options.element('paper-icon-item[name="delete"]'); + await deleteButton.click(); + await dialog.waitForVisible(); + const confirmButton = await dialog.element('paper-button[name="confirm"]'); + await confirmButton.click(); } - reply(text) { - this.replyButton.waitForVisible(); - this.replyButton.scrollIntoView(); - this.replyButton.click(); - this.thread.waitForVisible(); - this.thread.writeComment(text); + async reply(text) { + const replyButton = await this.replyButton; + const thread = await this.thread; + await replyButton.waitForVisible(); + await replyButton.scrollIntoView(); + await replyButton.click(); + await thread.waitForVisible(); + await thread.writeComment(text); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_comment_thread.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_comment_thread.js index 439fdd70a5..19b2a20ec8 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_comment_thread.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_comment_thread.js @@ -1,43 +1,65 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../../base'; import DocumentComment from './document_comment'; /* eslint import/no-cycle: 0 */ export default class DocumentCommentThread extends BasePage { get loadMoreCommentsLink() { - return this.el.element('.more-content'); + return (async () => { + const moreContent = await this.el.element('.more-content'); + return moreContent; + })(); } get nbItems() { - const items = this.el.elements('nuxeo-document-comment'); - let count = 0; - items.forEach((item) => { - if (item.isVisible()) { - count++; + return (async () => { + await driver.pause(3000); + const items = await this.el.elements('nuxeo-document-comment'); + let count = 0; + for (let i = 0; i < items.length; i++) { + const item = await items[i].isVisible(); + if (item) { + count++; + } } - }); - return count; + return count; + })(); } get writingArea() { - return this.el.element('#inputContainer'); + return (async () => { + const inputContainer = await this.el.element('#inputContainer'); + return inputContainer; + })(); } - getComment(text, user) { - const comments = this.el.elements('nuxeo-document-comment'); - const match = comments.find((item) => { + async getComment(text, user) { + const comments = await this.el.elements('nuxeo-document-comment'); + let trueIndex; + for (let i = 0; i < comments.length; i++) { + const item = await comments[i]; const comment = new DocumentComment(item); - return comment.author.getText() === user && comment.text.getText() === text; - }); - if (match) { - return new DocumentComment(match); + const authorName = await comment.author; + const authorText = await authorName.getText(); + const commentText = await comment.text; + const textComment = await commentText.getText(); + if (authorText === user && textComment === text) { + trueIndex = i; + break; + } + } + if (trueIndex > -1) { + return new DocumentComment(comments[trueIndex]); } throw new Error(`No comment authored by "${user}" with the text "${text}" was found`); } - writeComment(text) { - this.writingArea.scrollIntoView(); - this.writingArea.click(); - fixtures.layouts.setValue(this.writingArea, text); - this.el.element('.input-area iron-icon[name="submit"]').waitForVisible(); - this.el.element('.input-area iron-icon[name="submit"]').click(); + async writeComment(text) { + const writingAreaContainer = await this.writingArea; + await writingAreaContainer.scrollIntoView(); + await writingAreaContainer.click(); + await fixtures.layouts.setValue(writingAreaContainer, text); + const inputArea = await this.el.element('.input-area iron-icon[name="submit"]'); + await inputArea.waitForVisible(); + await inputArea.click(); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_create.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_create.js index ff8dfbea67..d9bf2c5b2c 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_create.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_create.js @@ -2,8 +2,9 @@ import BasePage from '../../base'; import DocumentLayout from './document_layout'; export default class DocumentCreate extends BasePage { - getDoctypeButton(docType) { - return this.el.element(`div[name="typeSelection"] paper-button[name="${docType}"]`); + async getDoctypeButton(docType) { + const typeSelection = await this.el.$(`div[name="typeSelection"] paper-button[name="${docType}"]`); + return typeSelection; } layout(docType) { diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_form_layout.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_form_layout.js index 06c02afef2..ed8a205c8e 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_form_layout.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_form_layout.js @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../../base'; import DocumentLayout from './document_layout'; @@ -9,7 +10,7 @@ export default class DocumentFormLayout extends BasePage { } set title(title) { - return this.el.element('.input-element input').setValue(title); + return this.el.$('.input-element input').setValue(title); } get layout() { @@ -17,12 +18,21 @@ export default class DocumentFormLayout extends BasePage { } get errorMessages() { - return this.el.elements('#error .error').map((errorElt) => errorElt.getText()); + return (async () => { + const errorElements = await this.el.elements('#error .error'); + const errorTexts = []; + for (let i = 0; i < errorElements.length; i++) { + const errorElement = errorElements[i]; + const errorText = await errorElement.getText(); + errorTexts.push(errorText); + } + return errorTexts; + })(); } - save() { - const button = this.el.element('.actions #save'); - button.waitForVisible(); - button.click(); + async save() { + const button = await this.el.element('.actions #save'); + await button.waitForVisible(); + await button.click(); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_layout.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_layout.js index e1dd3dbfdd..f4a6d7b3cb 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_layout.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_layout.js @@ -1,29 +1,36 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../../base'; export default class DocumentLayout extends BasePage { - getField(field) { - driver.waitForExist(this._selector); - return this.el.$(`[name="${field}"]`); + async getField(field) { + await driver.waitForExist(this._selector); + const ele = await this.el; + const result = await ele.$(`[name="${field}"]`); + return result; } - getFieldValue(field) { - const fieldEl = this.getField(field); - return fixtures.layouts.getValue(fieldEl); + async getFieldValue(field) { + const fieldEl = await this.getField(field); + const finalFieldEle = await fixtures.layouts.getValue(fieldEl); + return finalFieldEle; } - setFieldValue(field, value) { - const fieldEl = this.getField(field); - fieldEl.waitForVisible(); - return fixtures.layouts.setValue(fieldEl, value); + async setFieldValue(field, value) { + const fieldEl = await this.getField(field); + await fieldEl.waitForVisible(); + const result = await fixtures.layouts.setValue(fieldEl, value); + return result; } - fillMultipleValues(table) { - table.rows().forEach((row) => { + async fillMultipleValues(table) { + const rows = table.rows(); + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; const fieldName = row[0]; - const fieldEl = this.getField(fieldName); - fieldEl.waitForVisible(); - fieldEl.scrollIntoView(); - return fixtures.layouts.setValue(fieldEl, row[1]); - }); + const fieldEl = await this.getField(fieldName); + await fieldEl.waitForVisible(); + await fieldEl.scrollIntoView(); + await fixtures.layouts.setValue(fieldEl, row[1]); + } } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_page.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_page.js index a94ce5bae7..253d823e37 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_page.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_page.js @@ -11,7 +11,7 @@ export default class DocumentPage extends BasePage { } get view() { - return new DocumentView(`${this._selector} nuxeo-document-view div#container`, this.docType); + return (async () => new DocumentView(`${this._selector} nuxeo-document-view div#container`, this.docType))(); } get metadata() { @@ -37,11 +37,17 @@ export default class DocumentPage extends BasePage { } get restoreVersionButton() { - return this.versionInfoBar.element('nuxeo-restore-version-button'); + return (async () => { + const versionInfoBar = await this.versionInfoBar; + return versionInfoBar.element('nuxeo-restore-version-button'); + })(); } get restoreVersionButtonConfirm() { - return this.versionInfoBar.element('nuxeo-restore-version-button paper-button[dialog-confirm]'); + return (async () => { + const versionInfoBar = await this.versionInfoBar; + return versionInfoBar.element('nuxeo-restore-version-button paper-button[dialog-confirm]'); + })(); } get info() { @@ -69,20 +75,29 @@ export default class DocumentPage extends BasePage { } get publicationsCount() { - const info = this.el.element('nuxeo-document-info'); - if (info) { - const items = this.el.elements('nuxeo-document-info .item'); - const pub = items.find((i) => i.element('label').getText() === 'Publications'); - if (pub) { - return parseInt( - pub - .element('div') - .getText() - .trim(), - 10, - ); + return (async () => { + const info = await this.el.element('nuxeo-document-info'); + if (info) { + const items = await this.el.elements('nuxeo-document-info .item'); + let pub; + for (let i = 0; i < items.length; i++) { + // eslint-disable-next-line no-await-in-loop + const itemText = await items[i].getText(); + if (itemText === 'Publications') { + pub = items[i]; + } + } + if (pub) { + return parseInt( + pub + .$('div') + .getText() + .trim(), + 10, + ); + } } - } - return 0; + return 0; + })(); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_permissions.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_permissions.js index e00c3dd998..43a2be1f9c 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_permissions.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_permissions.js @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../../base'; export default class DocumentPermissions extends BasePage { @@ -18,51 +19,78 @@ export default class DocumentPermissions extends BasePage { } get timeFrameButton() { - return this.el.element('paper-radio-button #radioContainer'); + return (async () => { + const ele = await this.el; + return ele.element('paper-radio-button #radioContainer'); + })(); } - permission(permission, name, timeFrame) { - return driver.waitUntil(() => { - const rows = this.el.elements('div.acl-table-row'); - return rows.find((row) => { - const nameCheck = name ? row.isExisting(`span.user[title="${name} - ${name}@test.com"]`) : true; - const permissionCheck = permission ? !!row.hasElementByTextContent('span.label', permission) : true; - // XXX should rely on a class or column header name - const timeFrameCheck = timeFrame ? !!row.hasElementByTextContent('span', permission) : true; - return nameCheck && permissionCheck && timeFrameCheck; - }); - }); + async hasElement(selector, textContent, currentElement) { + const elements = await currentElement.elements(selector); + let found = false; + for (let i = 0; i < elements.length; i++) { + const ele = await elements[i]; + const text = await ele.getText(); + if (text === textContent) { + found = true; + } + } + return found; + } + + async permission(permission, name, timeFrame) { + let found; + const rows = await this.el.elements('div.acl-table-row'); + for (let i = 0; i < rows.length; i++) { + const row = await rows[i]; + const nameEle = await row.isExisting(`span.user[title="${name} - ${name}@test.com"]`); + const nameCheck = name ? nameEle : true; + const contentEle = await this.hasElement('span.label', permission, row); + const permissionCheck = permission ? await !!contentEle : true; + // XXX should rely on a class or column header name + const timeFrameEle = await this.hasElement('span', permission, row); + const timeFrameCheck = timeFrame ? !!timeFrameEle : true; + if (nameCheck && permissionCheck && timeFrameCheck) { + found = row; + break; + } + } + return found; } - getField(field) { - this.el.waitForVisible(); + async getField(field) { + const ele = await this.el; + await ele.waitForVisible(); if (field === 'begin' || field === 'end') { - return this.el.element(`[id="${field}"]`); + return ele.element(`[id="${field}"]`); } - return this.el.element(`[name="${field}"]`); + return ele.element(`[name="${field}"]`); } - getEditField(field) { - this.el.waitForVisible(); + async getEditField(field) { + const ele = await this.el; + await ele.waitForVisible(); if (field === 'begin' || field === 'end') { - return this.el.element(`nuxeo-document-acl-table nuxeo-popup-permission [id="${field}"]`); + return ele.element(`nuxeo-document-acl-table nuxeo-popup-permission [id="${field}"]`); } - return this.el.element(`nuxeo-document-acl-table nuxeo-popup-permission [name="${field}"]`); + return ele.element(`nuxeo-document-acl-table nuxeo-popup-permission [name="${field}"]`); } - setFieldValue(field, value) { - const fieldEl = this.getField(field); - fieldEl.waitForVisible(); - return fixtures.layouts.setValue(fieldEl, value); + async setFieldValue(field, value) { + const fieldEl = await this.getField(field); + await fieldEl.waitForVisible(); + const finalSet = await fixtures.layouts.setValue(fieldEl, value); + return finalSet; } - editFieldValue(field, value) { - const fieldEl = this.getEditField(field); - fieldEl.waitForVisible(); - return fixtures.layouts.setValue(fieldEl, value); + async editFieldValue(field, value) { + const fieldEl = await this.getEditField(field); + await fieldEl.waitForVisible(); + const finalGet = await fixtures.layouts.setValue(fieldEl, value); + return finalGet; } - setPermissions(name, opts) { + async setPermissions(name, opts) { opts = opts || {}; const permission = opts.permission || ''; const timeFrame = opts.timeFrame || ''; @@ -70,35 +98,36 @@ export default class DocumentPermissions extends BasePage { const end = opts.end || ''; const { notify } = opts; if (name) { - this.setFieldValue('userGroup', name); + await this.setFieldValue('userGroup', name); } - this.setFieldValue('right', permission); - this.timeFrameButton.click(); + await this.setFieldValue('right', permission); + const timeButton = await this.timeFrameButton; + await timeButton.click(); if (timeFrame === 'datebased') { - this.setFieldValue('begin', begin); + await this.setFieldValue('begin', begin); if (end) { - this.setFieldValue('end', end); + await this.setFieldValue('end', end); } } - this.setFieldValue('notify', notify); + await this.setFieldValue('notify', notify); } - editPermissions(opts) { + async editPermissions(opts) { opts = opts || {}; const permission = opts.permission || ''; const timeFrame = opts.timeFrame || ''; const begin = opts.begin || ''; const end = opts.end || ''; const { notify } = opts; - this.editFieldValue('right', permission); - this.editFieldValue(timeFrame, timeFrame); + await this.editFieldValue('right', permission); + await this.editFieldValue(timeFrame, timeFrame); if (timeFrame === 'datebased') { - this.editFieldValue('begin', begin); + await this.editFieldValue('begin', begin); if (end) { - this.editFieldValue('end', end); + await this.editFieldValue('end', end); } } - this.editFieldValue('notify', notify); + await this.editFieldValue('notify', notify); } waitForVisible() { diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_publications.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_publications.js index e209fab4b4..3acee1a9c7 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_publications.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_publications.js @@ -1,51 +1,71 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../../base'; export default class DocumentPublications extends BasePage { get count() { - const rows = this.el.elements('nuxeo-data-table#table nuxeo-data-table-row:not([header])'); - return rows.filter((result) => result.getAttribute('hidden') === null).length; + return (async () => { + await driver.pause(2000); + let elementCount = 0; + const elementsHidden = await browser + .$$('nuxeo-data-table#table nuxeo-data-table-row:not([header])') + .map((img) => img.getAttribute('hidden')); + for (let i = 0; i < elementsHidden.length; i++) { + const row = elementsHidden[i]; + if (row === null) { + elementCount++; + } + } + return elementCount; + })(); } - hasPublication(path, rendition, version) { - return !!this.getPublicationRow(path, rendition, version); + async hasPublication(path, rendition, version) { + const pubicationRow = await !!this.getPublicationRow(path, rendition, version); + return pubicationRow; } - getPublicationRow(path, rendition, version) { - this.waitForVisible('nuxeo-data-table#table nuxeo-data-table-row:not([header])'); - const rows = this.el.elements('nuxeo-data-table#table nuxeo-data-table-row:not([header])'); - const result = rows.find((row) => { + async getPublicationRow(path, rendition, version) { + const ele = await this.el.$('nuxeo-data-table#table nuxeo-data-table-row:not([header])'); + await ele.waitForVisible(); + const rows = await this.el.$$('nuxeo-data-table#table nuxeo-data-table-row:not([header])'); + let index; + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; if (row.isVisible('nuxeo-data-table-cell a.path')) { - const foundPath = row.getText('nuxeo-data-table-cell a.path').toLowerCase(); - if (foundPath.indexOf(path.trim().toLowerCase()) !== 0) { - return false; + const foundPathEle = await row.$('nuxeo-data-table-cell a.path'); + const foundPath = await foundPathEle.getText(); + const foundPathLowerCase = await foundPath.trim().toLowerCase(); + if (foundPathLowerCase.indexOf(path.trim().toLowerCase()) !== 0) { + index = -1; } - const foundRendition = row - .getText('nuxeo-data-table-cell .rendition') - .trim() - .toLowerCase(); - if (foundRendition !== rendition.toLowerCase()) { - return false; + const foundRenditionEle = await row.$('nuxeo-data-table-cell .rendition'); + const foundRendition = await foundRenditionEle.getText(); + const foundRenditionLowerCase = foundRendition.trim().toLowerCase(); + if (foundRenditionLowerCase !== rendition.toLowerCase()) { + index = -1; } - const foundVersion = row - .getText('nuxeo-data-table-cell .version') - .trim() - .toLowerCase(); - if (foundVersion && version != null && foundVersion !== version.toLowerCase()) { - return false; + const foundVersionEle = await row.$('nuxeo-data-table-cell .version'); + const foundVersion = await foundVersionEle.getText(); + const foundVersionLowerCase = await foundVersion.trim().toLowerCase(); + if (foundVersionLowerCase && version != null && foundVersion !== version.toLowerCase()) { + index = -1; } - return true; + index = i; } - return false; - }); - return result; + } + if (index !== -1) { + return rows[index]; + } + return false; } - republish(path, rendition, version) { - const pubRow = this.getPublicationRow(path, rendition, version); + async republish(path, rendition, version) { + const pubRow = await this.getPublicationRow(path, rendition, version); if (pubRow) { - pubRow.waitForVisible('paper-button.republish'); - pubRow.element('paper-button.republish').click(); - driver.alertAccept(); + await pubRow.waitForVisible('paper-button.republish'); + const pubRowEle = await pubRow.element('paper-button.republish'); + await pubRowEle.click(); + await driver.alertAccept(); } else { throw new Error(`Could not find publication ${path} ${rendition} ${version}`); } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_task.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_task.js index ca835dd437..8a5bf941c5 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_task.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_task.js @@ -33,19 +33,28 @@ export default class DocumentTask extends BasePage { return this.el.element('#layout'); } - setUserOrGroup(userOrGroup) { - const fieldEl = this.el.element('[name="userGroup"]'); - fixtures.layouts.setValue(fieldEl, userOrGroup); - } - - actorExists(element, actor) { - const users = element.elements('nuxeo-user-tag .tag a'); - return users.some((user) => user.getText() === `${actor}`); - } - - performAction(name) { - this.taskLayout.waitForVisible(); - this.el.waitForVisible(`.options paper-button[name="${name}"]`); - this.el.element(`.options paper-button[name="${name}"]`).click(); + async setUserOrGroup(userOrGroup) { + const fieldEl = await this.el.element('[name="userGroup"]'); + await fixtures.layouts.setValue(fieldEl, userOrGroup); + } + + async actorExists(element, actor) { + const users = await element.elements('nuxeo-user-tag .tag a'); + for (let i = 0; i < users.length; i++) { + // eslint-disable-next-line no-await-in-loop + const user = await users[i].getText(); + if (user === actor) { + return true; + } + } + return false; + } + + async performAction(name) { + const layout = await this.taskLayout; + await layout.waitForVisible(); + const ele = await this.el.element(`.options paper-button[name="${name}"]`); + await ele.waitForVisible(); + await ele.click(); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_versions.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_versions.js index 4fd357150f..83c1851fcd 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_versions.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser/document_versions.js @@ -2,82 +2,108 @@ import BasePage from '../../base'; export default class DocumentVersions extends BasePage { get createVersionButton() { - return this.el.element('nuxeo-document-create-version'); + return this.el.$('nuxeo-document-create-version'); } get dialog() { - if (this.list.isVisible()) { - return this.el.element('nuxeo-document-versions-list nuxeo-document-create-version #dialog:not([aria-hidden])'); - } - return this.el.element('nuxeo-document-create-version #dialog:not([aria-hidden])'); + return (async () => { + if (await this.list.isVisible()) { + return this.el.$('nuxeo-document-versions-list nuxeo-document-create-version #dialog:not([aria-hidden])'); + } + return this.el.$('nuxeo-document-create-version #dialog:not([aria-hidden])'); + })(); } get dialogMajorOption() { - return this.dialog.element('paper-radio-button[name="major"]'); + return (async () => { + const dialog = await this.dialog; + const element = await dialog.$('paper-radio-button[name="major"]'); + return element; + })(); } get dialogMinorOption() { - return this.dialog.element('paper-radio-button[name="minor"]'); + return (async () => { + const dialog = await this.dialog; + const element = await dialog.$('paper-radio-button[name="minor"]'); + return element; + })(); } get dialogNextMajor() { - return this.dialog.element('#nextMajor'); + return (async () => { + const dialog = await this.dialog; + return dialog.$('#nextMajor'); + })(); } get dialogNextMinor() { - return this.dialog.element('#nextMinor'); + return (async () => { + const dialog = await this.dialog; + return dialog.$('#nextMinor'); + })(); } get dialogDismissButton() { - return this.dialog.element('paper-button[dialog-dismiss]'); + return this.dialog.$('paper-button[dialog-dismiss]'); } get dialogConfirmButton() { - return this.dialog.element('paper-button[dialog-confirm]'); + return (async () => { + const dialog = await this.dialog; + const element = await dialog.$('paper-button[dialog-confirm]'); + return element; + })(); } get toggle() { - return this.el.element('nuxeo-tag.toggle'); + return (async () => { + const ele = await this.el; + const toggleElement = await ele.$('nuxeo-tag.toggle'); + return toggleElement; + })(); } get list() { - return this.el.element('nuxeo-document-versions-list'); + return this.el.$('nuxeo-document-versions-list'); } get listCreateVersionButton() { - return this.list.element('nuxeo-document-create-version'); + return this.list.$('nuxeo-document-create-version'); } get listCount() { - return this.list.elements('div[name="version-item"]').length; + return this.list.$$('div[name="version-item"]').length; } get listItems() { - return this.list.element('#list-items'); + return this.list.$('#list-items'); } listItem(index) { - return this.list.element(`#version-id-${index}`); + return this.list.$(`#version-id-${index}`); } listItemTitle(index) { - return this.list.element(`#version-id-${index}.title`); + return this.list.$(`#version-id-${index}.title`); } - selectVersion(label) { - if (this.toggle.getText().trim() === label) { + async selectVersion(label) { + const toggleElement = await this.toggle; + const text = await toggleElement.getText(); + if ((await text.trim()) === label) { return true; } - this.listItems.waitForVisible('div[name="version-item"] .title'); - const items = this.listItems.elements('div[name="version-item"]'); - const version = items.find((item) => { - const foundLabel = item.getText('.title').trim(); - return foundLabel === label; - }); - if (!version) { + const listItems = await this.listItems; + await listItems.$('div[name="version-item"] .title').waitForVisible(); + const listItems1 = await this.listItems.$$('div[name="version-item"]'); + const itemsTitle = await browser.$$('div[name="version-item"]').map((img) => img.$('.title').getText()); + const index = itemsTitle.findIndex((currenTitle) => currenTitle === label); + if (index === -1) { throw Error(`Could not find version ${label}`); } - version.waitForVisible(); - version.click(); + const version = await listItems1[index]; + await version.waitForVisible(); + await version.click(); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/browser/publication_dialog.js b/packages/nuxeo-web-ui-ftest/pages/ui/browser/publication_dialog.js index 84ae9c521d..269cf64fab 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/browser/publication_dialog.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/browser/publication_dialog.js @@ -2,48 +2,43 @@ import BasePage from '../../base'; import DocumentVersions from './document_versions'; export default class PublicationDialog extends BasePage { - publish(target, rendition, version, override) { + async publish(target, rendition, version, override) { // set target - this.waitForVisible('#target'); - // XXX some times #target gets stale somewhere in between fetching it and setting the value... - driver.waitUntil(() => { - try { - const targetSelect = this.el.element('#target'); - fixtures.layouts.setValue(targetSelect, target); - return true; - } catch (e) { - return false; - } - }); + const targetSelect = await this.el.$('#target'); + await targetSelect.waitForVisible(); + await fixtures.layouts.setValue(targetSelect, target); // set rendition if (rendition) { - const renditionSelect = this.el.element('#rendition'); - fixtures.layouts.setValue(renditionSelect, rendition); + const renditionSelect = await this.el.$('#rendition'); + await fixtures.layouts.setValue(renditionSelect, rendition); } // set version if (version) { const versionsList = new DocumentVersions(`${this._selector} #version`); - versionsList.toggle.waitForVisible(); - versionsList.toggle.click(); - versionsList.list.waitForVisible(); - versionsList.selectVersion(version); + const versionListToggle = await versionsList.toggle; + await versionListToggle.waitForVisible(); + await versionListToggle.click(); + const list = await versionsList.list; + await list.waitForVisible(); + await versionsList.selectVersion(version); // XXX we need to wait for the version to change, otherwise we could be sending the wrong version - versionsList.waitForVisible('.toggle-text'); - driver.waitUntil(() => { - try { - return versionsList.el.element('.toggle-text').getText() === version; - } catch (e) { - return false; - } - }); + const ele = await versionsList.el.$('.toggle-text'); + await driver.pause(2000); + await ele.waitForVisible(); + const outputText = await ele.getText(); + if (outputText !== version) { + throw Error(`Could not find version ${version}`); + } } if (override) { - const overrideCheckbox = this.el.element('#override'); - fixtures.layouts.setValue(overrideCheckbox, true); + const overrideCheckbox = await this.el.$('#override'); + await fixtures.layouts.setValue(overrideCheckbox, true); } - this.el.waitForEnabled('#publish'); - this.el.click('#publish'); - return driver.waitForVisible('iron-overlay-backdrop', driver.options.waitForTimeout, true); + await this.el.waitForEnabled('#publish'); + const ele = await this.el.$('#publish'); + await ele.click(); + const result = await driver.waitForVisible('iron-overlay-backdrop', 30000, true); + return result; } waitForVisible() { diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/bulk_edit.js b/packages/nuxeo-web-ui-ftest/pages/ui/bulk_edit.js index a86176f384..153543c609 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/bulk_edit.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/bulk_edit.js @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../base'; export default class BulkEdit extends BasePage { @@ -6,7 +7,10 @@ export default class BulkEdit extends BasePage { } get dialog() { - return this.el.element('#dialog'); + return (async () => { + const ele = await this.el.element('#dialog'); + return ele; + })(); } get cancelButton() { @@ -14,62 +18,84 @@ export default class BulkEdit extends BasePage { } get saveButton() { - return this.el.element('.actions #save'); + return (async () => { + const ele = await this.el.element('.actions #save'); + return ele; + })(); } - getField(field) { - return this.el.$(`[name="${field}"]`); + async getField(field) { + const ele = await this.el; + const result = await ele.$(`[name="${field}"]`); + return result; } - getFieldValue(field) { - const fieldEl = this.getField(field); - return fixtures.layouts.getValue(fieldEl); + async getFieldValue(field) { + const fieldEl = await this.getField(field); + const finalFieldEle = await fixtures.layouts.getValue(fieldEl); + return finalFieldEle; } - setFieldValue(field, value) { - const fieldEl = this.getField(field); - fieldEl.waitForVisible(); - return fixtures.layouts.setValue(fieldEl, value); + async setFieldValue(field, value) { + const fieldEl = await this.getField(field); + await fieldEl.waitForVisible(); + const result = await fixtures.layouts.setValue(fieldEl, value); + return result; } - editMultipleOptions(table) { - table.rows().forEach((row) => { + async editMultipleOptions(table) { + const rows = table.rows(); + + for (let index = 0; index < rows.length; index++) { + const row = rows[index]; const [fieldName, fieldValue, action] = row; - const fieldEl = this.getField(fieldName); - fieldEl.waitForVisible(); - this.getBulkEditOptions(fieldName).scrollIntoView(); + const fieldEl = await this.getField(fieldName); + await fieldEl.waitForVisible(); + const bulkEditOption = await this.getBulkEditOptions(fieldName); + await bulkEditOption.scrollIntoView(); if (action === 'remove') { - this.getBulkEditOptions(fieldName).click(); - this.bulkEditOptionsList(fieldName, 'Empty value(s)').click(); + await bulkEditOption.click(); + const emptyField = await this.bulkEditOptionsList(fieldName, 'Empty value(s)'); + await emptyField.click(); } else if (action === 'addValues') { - this.getBulkEditOptions(fieldName).click(); - this.bulkEditOptionsList(fieldName, 'Add value(s)').click(); - fixtures.layouts.setValue(fieldEl, fieldValue); + await bulkEditOption.click(); + const addValueField = await this.bulkEditOptionsList(fieldName, 'Add value(s)'); + await addValueField.click(); + await fixtures.layouts.setValue(fieldEl, fieldValue); } else if (action === 'replace') { - fixtures.layouts.setValue(fieldEl, fieldValue); + await fixtures.layouts.setValue(fieldEl, fieldValue); } - }); + } } - getBulkEditOptions(field) { - let bulkWidget = this.el.element(`[name="${field}"]`).parentElement(); + async getBulkEditOptions(field) { + const fieldEle = await this.el.element(`[name="${field}"]`); + let bulkWidget = await fieldEle.parentElement(); // some elements generated in Studio are wrapped in divs - if (bulkWidget.getTagName() !== 'nuxeo-bulk-widget') { - bulkWidget = bulkWidget.parentElement(); + const bulkWidgetTag = await bulkWidget.getTagName(); + if (bulkWidgetTag !== 'nuxeo-bulk-widget') { + bulkWidget = await bulkWidget.parentElement(); } - return bulkWidget.$('nuxeo-select'); + const bulkWidgetSelect = await bulkWidget.$('nuxeo-select'); + return bulkWidgetSelect; } - bulkEditOptionsList(fieldName, editOption) { - driver.waitUntil(() => { - const els = driver.elements(`${this._selector} nuxeo-bulk-widget nuxeo-select paper-item`); - return els.length > 1; - }); - - const listItems = this.el - .element(`[name="${fieldName}"]`) - .parentElement() - .elements('nuxeo-select paper-item'); - return listItems.find((e) => e.getText() === editOption); + async bulkEditOptionsList(fieldName, editOption) { + const ele = await driver.elements(`${this._selector} nuxeo-bulk-widget nuxeo-select paper-item`); + if (ele.length > 1) { + const fieldNameElem = await this.el.element(`[name="${fieldName}"]`); + const parentElem = await fieldNameElem.parentElement(); + const listItems = await parentElem.elements('nuxeo-select paper-item'); + let foundElem; + for (let index = 0; index < listItems.length; index++) { + const elem = listItems[index]; + const currentElementText = await elem.getText(); + if (currentElementText === editOption) { + foundElem = elem; + } + } + return foundElem; + } + return false; } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/clipboard.js b/packages/nuxeo-web-ui-ftest/pages/ui/clipboard.js index bf6bd8a648..4854f1a436 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/clipboard.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/clipboard.js @@ -1,15 +1,20 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../base'; export default class Clipboard extends BasePage { get nbItems() { - const items = this.el.$$('#list .list-item'); - let count = 0; - items.forEach((item) => { - if (item.isVisible()) { - count++; + return (async () => { + await driver.pause(3000); + const items = await this.el.$$('#list .list-item'); + let count = 0; + for (let index = 0; index < items.length; index++) { + const isItemVisible = await items[index].isDisplayed(); + if (isItemVisible) { + count++; + } } - }); - return count; + return count; + })(); } get moveButton() { @@ -20,28 +25,34 @@ export default class Clipboard extends BasePage { return this.el.$('#paste'); } - move() { - const moveBtn = this.moveButton; - moveBtn.waitForVisible(); - moveBtn.waitForEnabled(); - moveBtn.click(); + async move() { + const moveBtn = await this.moveButton; + await moveBtn.waitForVisible(); + await moveBtn.waitForEnabled(); + await moveBtn.click(); } - paste() { - const copyBtn = this.pasteButton; - copyBtn.waitForVisible(); - copyBtn.waitForEnabled(); - copyBtn.click(); + async paste() { + const copyBtn = await this.pasteButton; + await copyBtn.waitForVisible(); + await copyBtn.waitForEnabled(); + await copyBtn.click(); } - removeItem(title) { - const items = this.el.$$('nuxeo-data-list#list .list-item'); - return items.some((item) => { - if (item.isVisible() && item.getText('.list-item-title').trim() === title) { - item.click('iron-icon.remove'); - return true; + async removeItem(title) { + const items = await this.el.$$('nuxeo-data-list#list .list-item'); + await driver.pause(2000); + let found = false; + for (let index = 0; index < items.length; index++) { + const itemVisible = await items[index].isVisible(); + const item = await items[index].$('.list-item-title'); + const itemText = await item.getText(); + if (itemVisible && itemText === title) { + const ele = await items[index].$('iron-icon.remove'); + await ele.click(); + found = true; } - return false; - }); + } + return found; } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/collections.js b/packages/nuxeo-web-ui-ftest/pages/ui/collections.js index 0c393659d1..284212a7e8 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/collections.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/collections.js @@ -1,61 +1,82 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../base'; export default class Collections extends BasePage { - waitForHasCollection(name, reverse) { - const { el } = this; - driver.waitUntil( - () => { - const collections = el.elements('span.collection-name'); + async waitForHasCollection(name, reverse) { + const el = await this.el; + + await driver.waitUntil( + async () => { + const collections = await el.$$('span.collection-name'); if (reverse) { - return collections.every((collection) => collection.getText().trim() !== name); + return collections.every(async (collection) => (await collection.getText()).trim() !== name); } - return collections.some((collection) => collection.getText().trim() === name); + return collections.some(async (collection) => (await collection.getText()).trim() === name); }, reverse ? 'There is such collection' : 'There is no such collection', + { + timeoutMsg: 'waitForHasCollection timedout', + }, ); return true; } - select(name) { - const el = this.el.element('#collectionsList span.title'); - if (el.getText().trim() === name) { - el.click(); - return true; + async select(name) { + const ele = await this.el; + const rows = await ele.$$('#collectionsList span.title'); + for (let i = 0; i < rows.length; i++) { + const el = rows[i]; + const textEle = await el.getText(); + if (textEle.trim() === name) { + await el.click(); + return true; + } } return false; } get isQueueMode() { - return this.el.isExisting('#membersList') && this.el.isVisible('#membersList'); + const abc = this.el.isExisting('#membersList') && this.el.isVisible('#membersList'); + return abc; } get queueCount() { - return this.el.elements('#membersList div').length; + return this.el.$$('#membersList div').length; } - waitForHasMember(doc, reverse) { - const { el } = this; - driver.waitUntil( - () => { - const members = el.elements('#membersList .list-item-title'); - if (reverse) { - return members.every((member) => member.getText().trim() !== doc.title); + async waitForHasMember(doc, reverse) { + await driver.pause(2000); + const result = await (async () => { + const ele = await this.el; + const entriesTitle = await ele.$$('#membersList .list-item-title').map((img) => img.getText()); + const index = await entriesTitle.findIndex((currenTitle) => currenTitle.trim() === doc.title); + if (reverse) { + if (index !== -1) { + return false; } - return members.some((member) => member.getText().trim() === doc.title); - }, - reverse ? 'There is such member in the collection' : 'There is no such member in the collection', - ); - return true; + } else { + if (index !== -1) { + return true; + } + return false; + } + return true; + })(); + return result; } - removeMember(doc) { - const members = this.el.elements('#membersList'); - return members.some((member) => { - if (member.isVisible('span.list-item-title') && member.getText('span.list-item-title').trim() === doc.title) { - member.click('iron-icon.remove'); + async removeMember(doc) { + const members = await this.el.$$('#membersList'); + for (let i = 0; i < members.length; i++) { + const member = await members[i].$('span.list-item-title'); + const isRowVisibleEle = await member.isVisible(); + const getTextEle = await member.getText(); + if (isRowVisibleEle && getTextEle.trim() === doc.title) { + const buttonEle = await members[i].$('iron-icon.remove'); + await buttonEle.click(); return true; } - return false; - }); + } + return false; } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/create_dialog.js b/packages/nuxeo-web-ui-ftest/pages/ui/create_dialog.js index f56cc50b2b..c29d167de0 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/create_dialog.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/create_dialog.js @@ -1,3 +1,5 @@ +/* eslint-disable no-await-in-loop */ + import path from 'path'; import BasePage from '../base'; import DocumentCreate from './browser/document_create'; @@ -12,12 +14,13 @@ export default class CreateDialog extends BasePage { return new DocumentLayout('nuxeo-document-import'); } - importTab(name) { - return this.el.element(`paper-tab[name="${name}"]`); + async importTab(name) { + const ele = await this.el.element(`paper-tab[name="${name}"]`); + return ele; } get pages() { - return this.el.element('#holder iron-pages'); + return (async () => this.el.element('#holder iron-pages'))(); } /** @@ -29,10 +32,13 @@ export default class CreateDialog extends BasePage { return this.el.element('#csvCreation'); } - importPage(name) { - const pageName = this.pages.element('.iron-selected').getAttribute('name'); + async importPage(name) { + const getPages = await this.pages; + const page = await getPages.element('.iron-selected'); + const pageName = await page.getAttribute('name'); if (pageName === name) { - return this.pages.element(`[name=${pageName}]`); + const pageEle = await getPages.element(`[name=${pageName}]`); + return pageEle; } throw new Error(`The "${name}" element could not be located. Received "${pageName}" instead`); } @@ -42,16 +48,19 @@ export default class CreateDialog extends BasePage { * * @deprecated since 3.0.3. Please use method upload instead. * */ - setFileToImport(file) { - const field = this.importCsvDialog.element('#dropzone #uploadFiles'); - field.waitForExist(); + + async setFileToImport(file) { + const CsvDialog = await this.importCsvDialog; + const field = await CsvDialog.element('#dropzone #uploadFiles'); + await field.waitForExist(); return field.chooseFile(path.resolve(fixtures.blobs.get(file))); } - upload(file, name) { - this.importPage(name).waitForVisible(); - const field = this.importPage(name).element('#dropzone #uploadFiles'); - field.waitForExist(); + async upload(file, name) { + const importPage = await this.importPage(name); + await importPage.waitForVisible(); + const field = await importPage.element('#dropzone #uploadFiles'); + await field.waitForExist(); // XXX we need to reset the input value to prevent duplicate upload of files (when the method is called recursively) browser.execute((el) => { el.value = ''; @@ -64,11 +73,14 @@ export default class CreateDialog extends BasePage { } get importCreateButtonProperties() { - return this.el.element('paper-button[name="createWithProperties"]'); + return (async () => this.el.$('paper-button[name="createWithProperties"]'))(); } get importCSVButton() { - return this.el.element('div[name="upload"] paper-button.primary'); + return (async () => { + const impCsvBtn = await this.el.element('div[name="upload"] paper-button.primary'); + return impCsvBtn; + })(); } get selectedCSVToImport() { @@ -76,11 +88,17 @@ export default class CreateDialog extends BasePage { } get selectedFileToImport() { - return this.el.element('div.file-to-import'); + return (async () => { + const filetoImp = await this.el.element('div.file-to-import'); + return filetoImp; + })(); } get importCloseButton() { - return this.el.element('div[name="progress"] paper-button.primary'); + return (async () => { + const impClose = await this.el.element('div[name="progress"] paper-button.primary'); + return impClose; + })(); } get importError() { @@ -88,7 +106,10 @@ export default class CreateDialog extends BasePage { } get importSuccess() { - return this.el.element('#progress div.successful'); + return (async () => { + const impSuccess = await this.el.element('#progress div.successful'); + return impSuccess; + })(); } get createButton() { @@ -100,18 +121,28 @@ export default class CreateDialog extends BasePage { } get selectAnAssetType() { - return this.el.element('nuxeo-select[name="assetType"]'); + return (async () => { + const assetElement = await this.el.$('nuxeo-select[name="assetType"]'); + return assetElement; + })(); } get applyAll() { - return this.el.element('paper-button[name="applyAll"]'); - } - - selectAssetType(val) { - driver.waitForVisible('nuxeo-select[id="docTypeDropdown"] paper-item'); - const selectasset = this.el - .elements('nuxeo-select[id="docTypeDropdown"] paper-item[role="option"]') - .find((e) => e.getText() === val); - selectasset.click(); + return (async () => this.el.$('paper-button[name="applyAll"]'))(); + } + + async selectAssetType(val) { + await driver.waitForVisible('nuxeo-select[id="docTypeDropdown"] paper-item'); + const selectAssetElements = await this.el.elements('nuxeo-select[id="docTypeDropdown"] paper-item[role="option"]'); + let selectAsset; + for (let i = 0; i < selectAssetElements.length; i++) { + const e = selectAssetElements[i]; + const text = await e.getText(); + if (text === val) { + selectAsset = e; + break; + } + } + await selectAsset.click(); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/drawer.js b/packages/nuxeo-web-ui-ftest/pages/ui/drawer.js index 93d82511c9..8e59463ecd 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/drawer.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/drawer.js @@ -7,11 +7,14 @@ import Tasks from './tasks'; export default class Drawer extends BasePage { get menu() { - return this.el.$('#menu'); + return (async () => { + const menuEl = await this.el.$('#menu'); + return menuEl; + })(); } get pages() { - return this.el.$('iron-pages'); + return (async () => this.el.$('iron-pages'))(); } get logo() { @@ -31,7 +34,10 @@ export default class Drawer extends BasePage { } get administration() { - return this._section('administration'); + return (async () => { + const section = await this._section('administration'); + return section; + })(); } get recents() { @@ -51,25 +57,33 @@ export default class Drawer extends BasePage { } get personal() { - return this._section('personalWorkspace'); + return (async () => { + const personal = await this._section('personalWorkspace'); + return personal; + })(); } get profile() { return this._section('profile'); } - open(name) { - this.menu.waitForVisible(); - const section = this._section(name); - if (!section.isVisible()) { - this.menu.$(`nuxeo-menu-icon[name='${name}']`).click(); + async open(name) { + const currentMenu = await this.menu; + await currentMenu.waitForVisible(); + const section = await this._section(name); + const isVisible = await section.isVisible(); + if (!isVisible) { + const menu = await this.menu; + const buttonToclick = await menu.$(`nuxeo-menu-icon[name='${name}']`); + buttonToclick.click(); } - section.waitForVisible(); return section; } - _section(name) { - return this.pages.$(`[name='${name}']`); + async _section(name) { + const page = await this.pages; + const section = await page.$(`[name='${name}']`); + return section; } _search(name) { diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/favorites.js b/packages/nuxeo-web-ui-ftest/pages/ui/favorites.js index 9a638faf63..2762df7a91 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/favorites.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/favorites.js @@ -1,30 +1,46 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../base'; export default class Favorites extends BasePage { - hasDocument(doc) { - this.waitForVisible(); - return this._hasDocument(doc, this.el); + async hasDocument(doc) { + await this.waitForVisible(); + const titleTextEle = await this._hasDocument(doc, this.el); + return titleTextEle; } - removeDocument(doc) { - this.waitForVisible(); - const favorites = this.el.elements('#favoritesList'); - return favorites.some((favorite) => { - if (this._hasDocument(doc, this.el)) { - favorite.click('iron-icon.remove'); - driver.waitUntil(() => !this._hasDocument(doc, this.el)); + async removeDocument(doc) { + await this.waitForVisible(); + const favorites = await this.el.elements('#favoritesList'); + for (let i = 0; i < favorites.length; i++) { + const favorite = favorites[i]; + const hasDocumentEle = await this._hasDocument(doc, this.el); + if (hasDocumentEle) { + const ele = await favorite.$('iron-icon.remove'); + await ele.click(); + await driver.waitUntil( + async () => { + const hasDocumentEleResult = await this._hasDocument(doc, this.el); + return !hasDocumentEleResult; + }, + { + timeoutMsg: 'removeDocument timedout', + }, + ); return true; } return false; - }); + } } // prevent usage of this.el inside waitUntil - _hasDocument(doc, el) { - const favorites = el.$$('.list-item'); - return favorites.some((favorite) => { - const title = favorite.$('.list-item-title'); - return title.isVisible() && title.getText().trim() === doc.title; - }); + async _hasDocument(doc, el) { + const favorites = await el.$$('.list-item'); + for (let i = 0; i < favorites.length; i++) { + const favorite = favorites[i]; + const title = await favorite.$('.list-item-title'); + const isVisible = await title.isVisible(); + const text = await title.getText(); + return isVisible && text.trim() === doc.title; + } } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/group.js b/packages/nuxeo-web-ui-ftest/pages/ui/group.js index 7526633ed3..0c78299813 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/group.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/group.js @@ -23,7 +23,10 @@ export default class Group extends BasePage { } get editGroupButton() { - return this.el.element('#editGroupButton'); + return (async () => { + const editEle = await this.el.element('#editGroupButton'); + return editEle; + })(); } get editGroupLabel() { @@ -31,40 +34,60 @@ export default class Group extends BasePage { } get editGroupDialogButton() { - return this.el.element('#editGroupDialog paper-button.primary'); + return (async () => { + const groupDialogEle = await this.el.element('#editGroupDialog paper-button.primary'); + return groupDialogEle; + })(); } get deleteGroupButton() { - return this.el.element('#deleteGroupButton'); + return (async () => { + const deleteGroupEle = await this.el.element('#deleteGroupButton'); + return deleteGroupEle; + })(); } get confirmDeleteGroupButton() { - return this.el.element('#deleteGroupDialog paper-button'); + return (async () => { + const confirmButtonEle = await this.el.element('#deleteGroupDialog paper-button'); + return confirmButtonEle; + })(); } - fillMultipleValues(table) { - table.rows().forEach((row) => { + async fillMultipleValues(table) { + table.rows().forEach(async (row) => { if (row[0] === 'groupName') { // eslint-disable-next-line prefer-destructuring global.groups[row[1]] = row[1]; } - const fieldEl = this.getField(row[0]); - fieldEl.waitForVisible(); - return fixtures.layouts.setValue(fieldEl, row[1]); + const fieldEl = await this.getField(row[0]); + await fieldEl.waitForVisible(); + const setEle = await fixtures.layouts.setValue(fieldEl, row[1]); + return setEle; }); } - searchFor(searchTerm) { - driver.waitForExist(this._selector); - driver.waitForVisible(this._selector); - const searchBox = this.el.element('nuxeo-user-group-search paper-input'); - searchBox.waitForVisible(); - return fixtures.layouts.setValue(searchBox, searchTerm); + async searchFor(searchTerm) { + await driver.waitForExist(this._selector); + await driver.waitForVisible(this._selector); + const searchBox = await this.el.element('nuxeo-user-group-search paper-input'); + await searchBox.waitForVisible(); + const setEle = await fixtures.layouts.setValue(searchBox, searchTerm); + return setEle; } - searchResult(searchTerm) { - const match = (e) => e.getText() === searchTerm; - driver.waitUntil(() => this.el.elements('nuxeo-card[name="groups"] .table [name="id"]').some(match)); - return this.el.elements('nuxeo-card[name="groups"] .table [name="id"]').find(match); + async searchResult(searchTerm) { + const match = async (e) => (await e.getText()) === searchTerm; + await driver.waitUntil( + async () => { + const tableEle = await this.el.elements('nuxeo-card[name="groups"] .table [name="id"]'); + await tableEle.some(match); + }, + { + timeoutMsg: 'searchResult timedout', + }, + ); + const groupEle = await this.el.elements('nuxeo-card[name="groups"] .table [name="id"]'); + return groupEle.find(match); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/history_table.js b/packages/nuxeo-web-ui-ftest/pages/ui/history_table.js index a0d4ae6ce7..991c111b28 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/history_table.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/history_table.js @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../base'; export default class HistoryTable extends BasePage { @@ -10,21 +11,36 @@ export default class HistoryTable extends BasePage { } get isHistoryTableFilled() { - this.el.waitForDisplayed('#table nuxeo-data-table-row'); - return !this.el.$$('#table nuxeo-data-table-row').some((row) => row.getText().trim().length === 0); + return (async () => { + await this.el.waitForDisplayed('#table nuxeo-data-table-row'); + const tableRow = await this.el.$$('#table nuxeo-data-table-row'); + let found = false; + for (let index = 0; index < tableRow.length; index++) { + const itemText = await tableRow[index].getText(); + if (itemText.trim().length === 0) { + throw new 'table rows are empty'(); + } else { + found = true; + } + } + return found; + })(); } - waitForHasEntry(action, reverse) { - const { el } = this; - driver.waitUntil( - () => { - const cells = el.$$('#table nuxeo-data-table-cell'); + async waitForHasEntry(action, reverse) { + const el = await this.el; + await driver.waitUntil( + async () => { + const cells = await el.$$('#table nuxeo-data-table-cell'); if (reverse) { - return cells.every((cell) => cell.getText().trim() !== action); + return cells.every(async (cell) => (await cell.getText()).trim() !== action); } - return cells.some((cell) => cell.getText().trim() === action); + return cells.some(async (cell) => (await cell.getText()).trim() === action); }, reverse ? 'The history does have such entry' : 'The history does not have such entry', + { + timeoutMsg: 'waitForHasEntry timedout', + }, ); return true; } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/home.js b/packages/nuxeo-web-ui-ftest/pages/ui/home.js index b7ade75c27..ff28cd2aba 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/home.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/home.js @@ -1,7 +1,8 @@ import BasePage from '../base'; export default class Home extends BasePage { - card(contentId) { - return this.el.element(`#${contentId}`); + async card(contentId) { + const cardEle = await this.el.element(`#${contentId}`); + return cardEle; } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/note_editor.js b/packages/nuxeo-web-ui-ftest/pages/ui/note_editor.js index 91bb0e4da8..7153458dbb 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/note_editor.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/note_editor.js @@ -7,34 +7,44 @@ export default class NoteEditor extends BasePage { } get textarea() { - return this.el.element('#textarea'); + return this.el.$('#textarea'); } get editButton() { - return this.el.element('#editNote'); + return (async () => { + const editButton = await this.el.element('#editNote'); + return editButton; + })(); } - hasContent(content) { - const editor = this.el.element('#editor'); - editor.waitForVisible(); - driver.waitUntil(() => { - try { - return editor.getHTML(false) === content; - } catch (e) { - return false; - } - }, 'The editor does not have such content'); + async hasContent(content) { + const editor = await this.el.element('#editor'); + await editor.waitForVisible(); + await driver.waitUntil( + async () => { + try { + const result = (await editor.getHTML(false)) === content; + return result; + } catch (e) { + return false; + } + }, + { + timeoutMsg: 'The editor does not have such content', + }, + ); return true; } - edit() { - this.editButton.waitForVisible(); - this.editButton.click(); + async edit() { + const editButtonEle = await this.editButton; + await editButtonEle.waitForVisible(); + await editButtonEle.click(); } - save() { - const button = this.el.element('paper-button[name="editorSave"]'); - button.waitForVisible(); - button.click(); + async save() { + const button = await this.el.$('paper-button[name="editorSave"]'); + await button.waitForVisible(); + await button.click(); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/oauth2/user_authorized_apps.js b/packages/nuxeo-web-ui-ftest/pages/ui/oauth2/user_authorized_apps.js index 47b972aa1a..a1c389c09f 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/oauth2/user_authorized_apps.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/oauth2/user_authorized_apps.js @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../../base'; class AuthorizedApp { @@ -6,30 +7,49 @@ class AuthorizedApp { } get name() { - return this.el.elements('nuxeo-data-table-cell')[0].getText(); + return (async () => { + const eles = await this.el.elements('nuxeo-data-table-cell'); + const ele = await eles[0]; + const eleText = await ele.getText(); + return eleText; + })(); } get authorizationDate() { return this.el.elements('nuxeo-data-table-cell')[1].getText(); } - revokeButton() { - return this.el.element('paper-icon-button[name="revoke"]'); + async revokeButton() { + return (async () => { + const ele = await this.el.element('paper-icon-button[name="revoke"]'); + return ele; + })(); } } export default class UserAuthorizedApps extends BasePage { - getApps(appName) { - this.el.waitForVisible('nuxeo-data-table nuxeo-data-table-row'); - let apps = this.el - .elements('nuxeo-data-table nuxeo-data-table-row') - .splice(1) // skip the header - .map((el) => new AuthorizedApp(el)) // and map every element to a wrapper we can work with - .filter((app) => !!app.name.trim()); - // because clients are update after tokens, there might be empty rows that must be filtered + async getApps(appName) { + const elEx = await this.el; + await elEx.waitForVisible('nuxeo-data-table nuxeo-data-table-row'); + const appsNew = await this.el + .$$('nuxeo-data-table nuxeo-data-table-row:not([header])') + .map((el) => new AuthorizedApp(el)); + const filterAppNames = []; + const filterApps = []; + const apps = await appsNew.filter(async (app) => !!(await app.name).trim()); + for (let i = 0; i < apps.length; i++) { + const app = await apps[i]; + const appText = await app.el.$('nuxeo-data-table-cell').getText(); + if (appText.trim() !== '') { + filterAppNames.push(app); + } + if (appName === appText) { + filterApps.push(app); + } + } if (appName) { - apps = apps.filter((app) => app.name === appName); + return filterApps; } - return apps; + return filterAppNames; } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/oauth2/user_cloud_services.js b/packages/nuxeo-web-ui-ftest/pages/ui/oauth2/user_cloud_services.js index ae5d013189..c497caf254 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/oauth2/user_cloud_services.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/oauth2/user_cloud_services.js @@ -1,3 +1,4 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../../base'; class Token { @@ -13,20 +14,32 @@ class Token { return this.el.elements('nuxeo-data-table-cell')[0].getText(); } - deleteButton() { - return this.el.element('paper-icon-button[name="delete"]'); + async deleteButton() { + const deleteEle = await this.el.element('paper-icon-button[name="delete"]'); + return deleteEle; } } export default class UserCloudServices extends BasePage { - getTokens(user, provider) { - this.el.waitForVisible('nuxeo-data-table nuxeo-data-table-row'); - let tokens = this.el - .elements('nuxeo-data-table nuxeo-data-table-row') - .splice(1) // skip the header - .map((el) => new Token(el)); // and map every element to a wrapper we can work with - tokens = tokens.filter( - (token) => (user ? token.userId === user : true) && (provider ? token.providerId === provider : true), + async getTokens(user, provider) { + await driver.pause(3000); + const ele = await this.el; + await ele.waitForVisible('nuxeo-data-table nuxeo-data-table-row'); + const rowElements = await ele.elements('nuxeo-data-table nuxeo-data-table-row'); + const spliceEle = rowElements.splice(1); // skip the header + const mapsEle = spliceEle.map((el) => new Token(el)); + const tokenCells = await this.el + .$$('nuxeo-data-table nuxeo-data-table-row:not([header])') + .map((img) => img.$$('nuxeo-data-table-cell')); + const cellProvider = []; + const cellUser = []; + for (let i = 0; i < tokenCells.length; i++) { + cellProvider.push(await tokenCells[i][0].getText()); + cellUser.push(await tokenCells[i][1].getText()); + } + const tokens = await mapsEle.filter( + (token, index) => + (user ? cellUser[index] === user : true) && (provider ? cellProvider[index] === provider : true), ); return tokens; } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/recents.js b/packages/nuxeo-web-ui-ftest/pages/ui/recents.js index 88d6926a41..df3a3873e2 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/recents.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/recents.js @@ -2,39 +2,50 @@ import BasePage from '../base'; export default class Recents extends BasePage { get nbItems() { - const items = this.el.elements('#recentDocumentsList .list-item'); - let count = 0; - items.forEach((item) => { - if (item.isVisible()) { - count++; + return (async () => { + await driver.pause(2000); + const items = await this.el.elements('#recentDocumentsList .list-item'); + let count = 0; + for (let i = 0; i < items.length; i++) { + // eslint-disable-next-line no-await-in-loop + const item = await items[i].isVisible(); + if (item) { + count++; + } } - }); - return count; + return count; + })(); } - select(name) { - const entries = this.el.elements('#recentDocumentsList .list-item-title'); - const doc = entries.find((entry) => entry.getText().trim() === name); - if (doc) { - doc.click(); + async select(name) { + const entries = await this.el.$$('#recentDocumentsList .list-item-title'); + const entriesTitle = await this.el.$$('#recentDocumentsList .list-item-title').map((img) => img.getText()); + const index = entriesTitle.findIndex((currenTitle) => currenTitle.trim() === name); + if (index !== -1) { + await entries[index].click(); return true; } return false; } - waitForHasMember(title, reverse) { - driver.waitUntil( - () => { - const members = this.el.elements('#recentDocumentsList .list-item-title'); - if (reverse) { - return members.every((member) => member.getText().trim() !== title); + async waitForHasMember(title, reverse) { + await driver.pause(2000); + const result = await (async () => { + const ele = await this.el; + const entriesTitle = await ele.$$('#recentDocumentsList .list-item-title').map((img) => img.getText()); + const index = await entriesTitle.findIndex((currenTitle) => currenTitle.trim() === title); + if (reverse) { + if (index !== -1) { + return false; + } + } else { + if (index !== -1) { + return true; } - return members.some((member) => member.getText().trim() === title); - }, - reverse - ? 'There is such member in the recently viewed list' - : 'There is no such member in the recently viewed list', - ); - return true; + return false; + } + return true; + })(); + return result; } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/results.js b/packages/nuxeo-web-ui-ftest/pages/ui/results.js index 1d7a2609ec..cfab8e18ee 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/results.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/results.js @@ -1,105 +1,147 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../base'; export default class Results extends BasePage { get noResults() { // XXX using a more specific selector to return the visible label - return this.el.element('div.emptyResult:not([style=""])'); + return this.el.$('div.emptyResult:not([style=""])'); } get actions() { - return this.el.element('slot[name="actions"]'); + return this.el.$('slot[name="actions"]'); } get displayModes() { - return this.el.elements('div.resultActions paper-icon-button.displayMode'); + return (async () => { + const ele = await this.el.$$('div.resultActions paper-icon-button.displayMode'); + return ele; + })(); } get displayMode() { - driver.waitUntil(() => this.displayModes.some((displayMode) => displayMode.isVisible())); - const displayMode = this.displayModes.filter((result) => result.getAttribute('disabled') !== null); - return displayMode[0] - .getAttribute('title') - .replace('Switch to ', '') - .replace(/ view| View/, '') - .toLowerCase(); + return (async () => { + const displayModesRows = await this.displayModes; + const displayModeArr = []; + for (let i = 0; i < displayModesRows.length; i++) { + const row = displayModesRows[i]; + if ((await row.getAttribute('disabled')) !== null) { + displayModeArr.push(row); + } + } + const attr = await displayModeArr[0].getAttribute('title'); + return attr + .replace('Switch to ', '') + .replace(/ view| View/, '') + .toLowerCase(); + })(); } get toggleTableView() { - return this.displayModes.find((e) => e.getAttribute('title').includes('Table View')); + return (async () => { + const displayModesRows = await this.displayModes; + for (let i = 0; i < displayModesRows.length; i++) { + const row = displayModesRows[i]; + const attr = await row.getAttribute('title'); + if (attr.includes('Table View')) { + return row; + } + } + })(); } get toggleColumnSettings() { - return this.el.element('nuxeo-data-table[name="table"] #toggleColSettings'); + return this.el.$('nuxeo-data-table[name="table"] #toggleColSettings'); } get columnsSettingsPopup() { - return this.el.element('nuxeo-data-table[name="table"] #columnsSettingsPopup'); + return this.el.$('nuxeo-data-table[name="table"] #columnsSettingsPopup'); } get columnsCloseButton() { - return this.columnsSettingsPopup.element('paper-button.primary'); + return this.columnsSettingsPopup.$('paper-button.primary'); } - getResults(displayMode) { + async getResults(displayMode) { switch (displayMode) { case 'grid': - return this.el.elements('nuxeo-document-grid-thumbnail, nuxeo-justified-grid-item'); + return this.el.$$('nuxeo-document-grid-thumbnail, nuxeo-justified-grid-item'); case 'list': - return this.el.elements('nuxeo-document-list-item'); + return this.el.$$('nuxeo-document-list-item'); default: - return this.el.elements('nuxeo-data-table[name="table"] div.item'); + return this.el.$$('nuxeo-data-table[name="table"] div.item'); } } - getColumnCheckbox(heading) { - this.el.waitForVisible('nuxeo-data-table[name="table"] nuxeo-dialog[id="columnsSettingsPopup"]'); - const tr = this.el - .elements('nuxeo-data-table[name="table"] nuxeo-dialog[id="columnsSettingsPopup"] tr') - .find((e) => e.getText() === heading); - tr.waitForVisible('paper-checkbox'); - return tr.element('paper-checkbox'); + async getColumnCheckbox(heading) { + const ele = await this.el; + await ele.$('nuxeo-data-table[name="table"] nuxeo-dialog[id="columnsSettingsPopup"]').waitForVisible(); + const rows = await ele.$$('nuxeo-data-table[name="table"] nuxeo-dialog[id="columnsSettingsPopup"] tr'); + const elementTitle = await ele + .$$('nuxeo-data-table[name="table"] nuxeo-dialog[id="columnsSettingsPopup"] tr') + .map((img) => img.getText()); + const index = elementTitle.findIndex((currenTitle) => currenTitle === heading); + const result = await rows[index].$('paper-checkbox'); + await result.waitForVisible(); + return result; } - checkColumnCheckbox(heading) { - const checkbox = this.getColumnCheckbox(heading); - if (checkbox.getAttribute('checked') === null) { + async checkColumnCheckbox(heading) { + const checkbox = await this.getColumnCheckbox(heading); + if ((await checkbox.getAttribute('checked')) === null) { return checkbox.click(); } } - getResultsColumn(heading) { - this.el.waitForVisible('nuxeo-data-table[name="table"] nuxeo-data-table-row[header]'); - const row = this.el.element('nuxeo-data-table[name="table"] nuxeo-data-table-row[header]'); - row.waitForVisible('nuxeo-data-table-cell:not([hidden])'); - return row.elements('nuxeo-data-table-cell:not([hidden])').find((e) => e.getText() === heading); - } - - resultsCount(displayMode) { - const rows = this.getResults(displayMode); - return rows ? rows.filter((result) => result.getAttribute('hidden') === null).length : 0; + async getResultsColumn(heading) { + const ele = await this.el; + await ele.$('nuxeo-data-table[name="table"] nuxeo-data-table-row[header]').waitForVisible(); + const row = await ele.$('nuxeo-data-table[name="table"] nuxeo-data-table-row[header]'); + const rowElement = await row.$('nuxeo-data-table-cell:not([hidden])'); + await rowElement.waitForVisible(); + const titleRows = await row.$$('nuxeo-data-table-cell:not([hidden])'); + const rowTitles = await row.$$('nuxeo-data-table-cell:not([hidden])').map((img) => img.getText()); + const index = rowTitles.findIndex((currenTitle) => currenTitle === heading); + const result = await titleRows[index]; + return result; + } + + async resultsCount(displayMode) { + const rows = await this.getResults(displayMode); + let elementCount = 0; + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + const elementsHidden = await row.getAttribute('hidden'); + if (elementsHidden === null) { + elementCount++; + } + } + return elementCount; } get resultsCountLabel() { - return this.el.element('div.resultActions .resultsCount'); + return (async () => { + const ele = await this.el; + return ele.$('div.resultActions .resultsCount'); + })(); } - deleteDocuments() { - const el = this.deleteDocumentsButton; - el.waitForVisible(); - el.click(); + async deleteDocuments() { + const el = await this.deleteDocumentsButton; + await el.waitForVisible(); + await el.click(); } - untrashDocuments() { - const el = this.untrashDocumentsButton; - el.waitForVisible(); - el.click(); + async untrashDocuments() { + const el = await this.untrashDocumentsButton; + await el.waitForVisible(); + await el.click(); } get deleteDocumentsButton() { - return this.el.element('nuxeo-delete-documents-button[hard]'); + return this.el.$('nuxeo-delete-documents-button[hard]'); } get untrashDocumentsButton() { - return this.el.element('nuxeo-untrash-documents-button'); + return this.el.$('nuxeo-untrash-documents-button'); } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/search.js b/packages/nuxeo-web-ui-ftest/pages/ui/search.js index 9d2686675f..02abf24cad 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/search.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/search.js @@ -8,17 +8,30 @@ export default class Search extends Results { } get saveSearchAsButton() { - driver.waitForVisible('#actions paper-button'); - return driver.elements('#actions paper-button').find((e) => e.getText() === 'Save As'); + return (async () => { + const eles = await driver.$('#actions paper-button'); + await eles.waitForVisible(); + const buttons = await driver.$$('#actions paper-button'); + const rowTitles = await driver.$$('#actions paper-button').map((img) => img.getText()); + const index = rowTitles.findIndex((currenTitle) => currenTitle === 'Save As'); + const result = await buttons[index]; + return result; + })(); } get confirmSaveSearchButton() { - driver.waitForVisible('#saveDialog paper-button.primary'); - return driver.element('#saveDialog paper-button.primary'); + return (async () => { + const ele = await driver.$('#saveDialog paper-button.primary'); + await ele.waitForVisible(); + return ele; + })(); } get menuButton() { - return this.el.element('#menuButton'); + return (async () => { + const ele = await this.el; + return ele.element('#menuButton'); + })(); } get savedSearchActionButton() { @@ -26,30 +39,42 @@ export default class Search extends Results { } get shareAction() { - driver.waitForVisible('nuxeo-saved-search-actions paper-item'); - return driver.elements('nuxeo-saved-search-actions paper-item').find((e) => e.getText() === 'Share'); + return (async () => { + const ele = await driver.$('nuxeo-saved-search-actions paper-item'); + await ele.waitForVisible(); + const buttons = await driver.$$('nuxeo-saved-search-actions paper-item'); + const rowTitles = await driver.$$('nuxeo-saved-search-actions paper-item').map((img) => img.getText()); + const index = rowTitles.findIndex((currenTitle) => currenTitle === 'Share'); + const result = await buttons[index]; + return result; + })(); } get permissionsView() { return new DocumentPermissions(`${this._selector} nuxeo-document-permissions`); } - getSavedSearch(savedSearchName) { - driver.waitUntil(() => { - const els = driver.elements(`${this._selector} #actionsDropdown paper-item`); - return els.length > 1; - }); - return this.el.elements('#actionsDropdown paper-item').find((e) => e.getText() === savedSearchName); + async getSavedSearch(savedSearchName) { + const selector = await this._selector; + const els = await driver.elements(`${selector} #actionsDropdown paper-item`); + if (els.length > 1) { + return els[1]; + } + const ele = await this.el; + const dropdownList = await ele.elements('#actionsDropdown paper-item'); + const dropdownElenent = await dropdownList.find(async (e) => (await e.getText()) === savedSearchName); + return dropdownElenent; } enterInput(text) { return driver.keys(text); } - getField(field) { - driver.waitForExist(this._selector); - driver.waitForVisible(this._selector); - return this.el.element(`[name="${field}"]`); + async getField(field) { + await driver.waitForExist(this._selector); + await driver.waitForVisible(this._selector); + const ele = await this.el.$(`[name="${field}"]`); + return ele; } getFieldValue(field) { @@ -58,29 +83,37 @@ export default class Search extends Results { return fixtures.layouts.getValue(fieldEl); } - setFieldValue(field, value) { - let fieldEl; - driver.waitUntil(() => { - fieldEl = this.getField(field); - return !!fieldEl; - }); - fieldEl.waitForVisible(); - fieldEl.scrollIntoView(); + async setFieldValue(field, value) { + const fieldEl = await this.getField(field); + await fieldEl.waitForVisible(); + await fieldEl.scrollIntoView(); return fixtures.layouts.setValue(fieldEl, value); } - search(searchType, searchTerm) { + async search(searchType, searchTerm) { if (searchType === 'fulltext') { - this.el.element('#searchInput .input-element input').waitForVisible(); - this.el.element('#searchInput .input-element input').setValue(searchTerm); - driver.keys('Enter'); + const searchInputEle = await this.el.$('#searchInput .input-element input'); + await searchInputEle.waitForVisible(); + await searchInputEle.setValue(searchTerm); + await driver.keys('Enter'); } else { - this.setFieldValue(searchType, searchTerm); + await this.setFieldValue(searchType, searchTerm); } } - quickSearchResultsCount() { - const rows = this.el.element('#results #selector').elements('a.item'); - return rows.filter((result) => result.getAttribute('hidden') === null).length; + async quickSearchResultsCount() { + const ele = await this.el; + const selector = await ele.element('#results #selector'); + const rows = await selector.elements('a.item'); + let count = 0; + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + // eslint-disable-next-line no-await-in-loop + const attr = await row.getAttribute('hidden'); + if (attr === null) { + count++; + } + } + return count; } } diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/selection.js b/packages/nuxeo-web-ui-ftest/pages/ui/selection.js index 7a88e7485d..41439fd05a 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/selection.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/selection.js @@ -4,38 +4,50 @@ import PublicationDialog from './browser/publication_dialog'; import { clickActionMenu } from '../helpers'; export default class Selection extends BasePage { - addToClipboard() { - this.el.element('nuxeo-clipboard-documents-button').click(); - this.waitForNotVisible(); + async addToClipboard() { + const button = await this.el.element('nuxeo-clipboard-documents-button'); + await button.click(); + await this.waitForNotVisible(); } get addDocumentsToCollectionButton() { - return this.el.element('nuxeo-add-to-collection-documents-button'); + return (async () => { + const thisEle = await this.el; + const documentsButtonEle = await thisEle.$('nuxeo-add-to-collection-documents-button'); + return documentsButtonEle; + })(); } get addToCollectionDialog() { - const button = this.addDocumentsToCollectionButton; - button.waitForVisible(); - if (!button.isExisting('#dialog') || !button.isVisible('#dialog')) { - button.click(); - } - const dialog = new AddToCollectionDialog(`${this._selector} nuxeo-add-to-collection-documents-button #dialog`); - dialog.waitForVisible(); - return dialog; + return (async () => { + const button = await this.addDocumentsToCollectionButton; + await button.waitForVisible(); + + if (!(await button.isExisting('#dialog')) || !(await button.isVisible('#dialog'))) { + await button.click(); + } + const dialog = new AddToCollectionDialog( + `${await this._selector} nuxeo-add-to-collection-documents-button #dialog`, + ); + await dialog.waitForVisible(); + return dialog; + })(); } - moveDown() { - this.el.waitForVisible('nuxeo-move-documents-down-button'); - this.el.element('nuxeo-move-documents-down-button').click(); + async moveDown() { + await this.el.waitForVisible('nuxeo-move-documents-down-button'); + const ele = await this.el.element('nuxeo-move-documents-down-button'); + await ele.click(); } - moveUp() { - this.el.waitForVisible('nuxeo-move-documents-up-button'); - this.el.element('nuxeo-move-documents-up-button').click(); + async moveUp() { + await this.el.waitForVisible('nuxeo-move-documents-up-button'); + const ele = await this.el.element('nuxeo-move-documents-up-button'); + await ele.click(); } - trashDocuments() { - this.clickResultsActionMenu('nuxeo-delete-documents-button'); + async trashDocuments() { + await this.clickResultsActionMenu('nuxeo-delete-documents-button'); } get trashDocumentsButton() { @@ -47,16 +59,21 @@ export default class Selection extends BasePage { } get publishDialog() { - if (!this.el.isExisting('#publishDialog') || !this.el.isVisible('#publishDialog')) { - this.clickResultsActionMenu('nuxeo-publish-button'); - } - const publishDialog = new PublicationDialog(`${this._selector} #publishDialog`); - publishDialog.waitForVisible(); - return publishDialog; + return (async () => { + const elementIsExisting = await this.el.isExisting('#publishDialog'); + const elementIsVisible = await this.el.isVisible('#publishDialog'); + if ((await !elementIsExisting) || (await !elementIsVisible)) { + await this.clickResultsActionMenu('nuxeo-publish-button'); + } + const publishDialog = new PublicationDialog(`${this._selector} #publishDialog`); + await publishDialog.waitForVisible(); + return publishDialog; + })(); } - clickResultsActionMenu(selector) { - clickActionMenu(this.el, selector); + async clickResultsActionMenu(selector) { + const ele = await this.el; + await clickActionMenu(ele, selector); } get compare() { diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/tasks.js b/packages/nuxeo-web-ui-ftest/pages/ui/tasks.js index 41644b4df2..435ed0bf76 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/tasks.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/tasks.js @@ -2,14 +2,19 @@ import BasePage from '../base'; export default class Tasks extends BasePage { get nbItems() { - const items = this.el.elements('#list .list-item'); - let count = 0; - items.forEach((item) => { - if (item.isVisible()) { - count++; + return (async () => { + await driver.pause(2000); + const items = await this.el.$$('#list .list-item'); + let count = 0; + for (let i = 0; i < items.length; i++) { + // eslint-disable-next-line no-await-in-loop + const item = await items[i].isVisible(); + if (item) { + count++; + } } - }); - return count; + return count; + })(); } get dashboardLink() { diff --git a/packages/nuxeo-web-ui-ftest/pages/ui/user.js b/packages/nuxeo-web-ui-ftest/pages/ui/user.js index 792a2c7a98..1e730f3498 100644 --- a/packages/nuxeo-web-ui-ftest/pages/ui/user.js +++ b/packages/nuxeo-web-ui-ftest/pages/ui/user.js @@ -1,16 +1,19 @@ +/* eslint-disable no-await-in-loop */ import BasePage from '../base'; export default class User extends BasePage { - getField(field, opts) { + async getField(field, opts) { opts = opts || {}; const parent = opts.parent || ''; - driver.waitForExist(this._selector); - driver.waitForVisible(this._selector); - this.el.waitForVisible(parent); + await driver.waitForExist(this._selector); + await driver.waitForVisible(this._selector); + await this.el.waitForVisible(parent); if (field === 'password' || field === 'passwordConfirmation') { - return this.el.element(`${parent} [id="${field}"]`); + const fieldEle = await this.el.element(`${parent} [id="${field}"]`); + return fieldEle; } - return this.el.element(`${parent} [name="${field}"]`); + const finalEle = await this.el.element(`${parent} [name="${field}"]`); + return finalEle; } get dropdown() { @@ -53,34 +56,40 @@ export default class User extends BasePage { return this.el.element('#deleteUserDialog paper-button'); } - fillMultipleValues(table, opts) { + async fillMultipleValues(table, opts) { opts = opts || {}; const parent = opts.parent || ''; - table.rows().forEach((row) => { + const rows = table.rows(); + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; if (row[0] === 'username') { - // eslint-disable-next-line prefer-destructuring + /* eslint-disable prefer-destructuring */ global.users[row[1]] = row[1]; - this.el.element('paper-toggle-button[name="password-toggle"]').waitForVisible(); - this.el.element('paper-toggle-button[name="password-toggle"]').click(); + const toggleEle = await this.el.element('paper-toggle-button[name="password-toggle"]'); + await toggleEle.waitForVisible(); + await toggleEle.click(); } - const fieldEl = this.getField(row[0], { parent }); - fieldEl.waitForVisible(); - return fixtures.layouts.setValue(fieldEl, row[1]); - }); + const fieldEl = await this.getField(row[0], { parent }); + await fieldEl.waitForVisible(); + await fixtures.layouts.setValue(fieldEl, row[1]); + } } - searchFor(searchTerm) { - driver.waitForExist(this._selector); - driver.waitForVisible(this._selector); - const searchBox = this.el.element('nuxeo-user-group-search nuxeo-input'); - searchBox.waitForVisible(); - return fixtures.layouts.setValue(searchBox, searchTerm); + async searchFor(searchTerm) { + await driver.waitForExist(this._selector); + await driver.waitForVisible(this._selector); + const searchBox = await this.el.element('nuxeo-user-group-search nuxeo-input'); + await searchBox.waitForVisible(); + const finaleEle = await fixtures.layouts.setValue(searchBox, searchTerm); + return finaleEle; } - searchResult(searchTerm) { - const match = () => - this.el.elements('nuxeo-card[name="users"] .table [name="id"]').find((e) => e.getText() === searchTerm); - driver.waitUntil(match); - return match(); + async searchResult(searchTerm) { + const ele = await this.el; + await driver.pause(3000); + const results = await ele.elements('nuxeo-card[name="users"] .table [name="id"]'); + + const match = await results.find(async (e) => (await e.getText()) === searchTerm); + return match; } } diff --git a/packages/nuxeo-web-ui-ftest/scripts/test.js b/packages/nuxeo-web-ui-ftest/scripts/test.js index 45cda73595..b40eb6de86 100755 --- a/packages/nuxeo-web-ui-ftest/scripts/test.js +++ b/packages/nuxeo-web-ui-ftest/scripts/test.js @@ -28,12 +28,10 @@ const fs = require('fs'); const path = require('path'); -const { spawn } = require('child_process'); const { execSync } = require('child_process'); const chromeLauncher = require('chrome-launcher'); const fetch = require('node-fetch'); - -const wdioBin = require.resolve('@wdio/cli/bin/wdio'); +const cli = require('@wdio/cli'); const argv = require('minimist')(process.argv.slice(2)); const defaultDef = './features/step_definitions'; @@ -114,25 +112,25 @@ if (process.env.DRIVER_VERSION == null) { console.log(`${version} detected.`); const match = version && version.match(/([0-9]+)\./); if (match) { - // const checkVersion = match[1]; - // we will revert this once driver issue is resolved. - const checkVersion = 114; + const checkVersion = match[1]; try { - done = fetch(`https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${checkVersion}`).then((response) => { - if (response.ok) { - return response - .text() - .then((newDriverVersion) => { - // eslint-disable-next-line no-console - console.log(`ChromeDriver ${newDriverVersion} needed.`); - process.env.DRIVER_VERSION = newDriverVersion; - }) - .catch((e) => { - console.error('unable to parse ChromeDriver version: ', e); - }); - } - console.error('unable to fetch ChromeDriver version: ', response); - }); + done = fetch(`https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_${checkVersion}`).then( + (response) => { + if (response.ok) { + return response + .text() + .then((newDriverVersion) => { + // eslint-disable-next-line no-console + console.log(`ChromeDriver ${newDriverVersion} needed.`); + process.env.DRIVER_VERSION = newDriverVersion; + }) + .catch((e) => { + console.error('unable to parse ChromeDriver version: ', e); + }); + } + console.error('unable to fetch ChromeDriver version: ', response); + }, + ); } catch (e) { console.error('unable to fetch ChromeDriver version: ', e); } @@ -140,12 +138,14 @@ if (process.env.DRIVER_VERSION == null) { } done.finally(() => { - const wdio = spawn('node', [wdioBin, ...args], { env: process.env, stdio: ['inherit', 'pipe', 'pipe'] }); - - wdio.stdout.pipe(process.stdout); - wdio.stderr.pipe(process.stderr); - - wdio.on('close', (code) => { - process.exit(code); - }); + const wdio = new cli.Launcher(args[0]); + wdio.run().then( + (code) => { + process.exit(code); + }, + (error) => { + console.error('Launcher failed to start the test', error.stacktrace); + process.exit(1); + }, + ); }); diff --git a/packages/nuxeo-web-ui-ftest/wdio-compat-plugin.js b/packages/nuxeo-web-ui-ftest/wdio-compat-plugin.js index 145d571455..25f37c8861 100644 --- a/packages/nuxeo-web-ui-ftest/wdio-compat-plugin.js +++ b/packages/nuxeo-web-ui-ftest/wdio-compat-plugin.js @@ -224,24 +224,27 @@ module.exports = class { 'waitForVisible', async function(...args) { let target = this; - if (typeof args[0] === 'string') { + if (typeof args[0] === 'string' && typeof target.waitForDisplayed !== 'function') { target = this.element(args.shift()); } const [timeout, reverse = false] = args; - return target.waitForDisplayed({ timeout, reverse }); + if (typeof target.waitForDisplayed === 'function') { + return target.waitForDisplayed({ timeout, reverse }); + } }, true, ); browser.addCommand( 'chooseFile', - function(...args) { + async function(...args) { let target = this; if (args.length > 1) { - target = this.element(args.shift()); + const argShift = args.shift(); + target = await this.element(argShift); } const [localFilePath] = args; - const remoteFile = browser.uploadFile(localFilePath); + const remoteFile = await browser.uploadFile(localFilePath); target.addValue(remoteFile); }, true, @@ -249,8 +252,9 @@ module.exports = class { browser.addCommand( 'hasElementByTextContent', - function(selector, textContent) { - return this.elements(selector).some((e) => e.getText() === textContent); + async function(selector, textContent) { + const ele = await this.elements(selector); + return ele.some((e) => e.getText() === textContent); }, true, ); diff --git a/packages/nuxeo-web-ui-ftest/wdio.conf.js b/packages/nuxeo-web-ui-ftest/wdio.conf.js index 2ab805c665..040e4c6d2c 100644 --- a/packages/nuxeo-web-ui-ftest/wdio.conf.js +++ b/packages/nuxeo-web-ui-ftest/wdio.conf.js @@ -27,6 +27,7 @@ const capability = { maxInstances: 1, browserName: process.env.BROWSER, acceptInsecureCerts: true, + browserVersion: 'stable', }; const options = {}; @@ -66,7 +67,7 @@ switch (capability.browserName) { // no default } -const TIMEOUT = process.env.TIMEOUT ? Number(process.env.TIMEOUT) : 20000; +const TIMEOUT = process.env.TIMEOUT ? Number(process.env.TIMEOUT) : 24000; // Allow overriding driver version const drivers = {}; @@ -100,7 +101,7 @@ exports.config = { // WebdriverIO allows it to run your tests in arbitrary locations (e.g. locally or // on a remote machine). runner: 'local', - + specs: ['../../ftest/features/**'], // check http://webdriver.io/guide/testrunner/debugging.html for more info on debugging with wdio debug: process.env.DEBUG, execArgv: process.env.DEBUG ? ['--inspect'] : [], @@ -179,17 +180,7 @@ exports.config = { // Services take over a specific job you don't want to take care of. They enhance // your test setup with almost no effort. Unlike plugins, they don't add new // commands. Instead, they hook themselves up into the test process. - services: [ - [ - 'selenium-standalone', - { - installArgs: { drivers }, - args: { drivers }, - }, - ], - [CompatService], - [ShadowService], - ], + services: [[CompatService], [ShadowService]], // // Framework you want to run your specs with. diff --git a/plugin/a11y/getDriverVersion.js b/plugin/a11y/getDriverVersion.js index 047d3fc358..440b5ef1e3 100644 --- a/plugin/a11y/getDriverVersion.js +++ b/plugin/a11y/getDriverVersion.js @@ -13,11 +13,10 @@ try { } const match = version && version.match(/([0-9]+)\./); if (match) { - // const checkVersion = match[1]; + const checkVersion = match[1]; // we will revert this once driver issue is resolved. - const checkVersion = 114; try { - fetch(`https://chromedriver.storage.googleapis.com/LATEST_RELEASE_${checkVersion}`).then((response) => { + fetch(`https://googlechromelabs.github.io/chrome-for-testing/LATEST_RELEASE_${checkVersion}`).then((response) => { if (response.ok) { return response .text() diff --git a/plugin/a11y/package.json b/plugin/a11y/package.json index e2a53ce366..b294f0bc78 100644 --- a/plugin/a11y/package.json +++ b/plugin/a11y/package.json @@ -2,7 +2,7 @@ "name": "@nuxeo/nuxeo-web-ui-a11y", "version": "1.0.0", "engines": { - "node": ">=10.23.0" + "node": ">=18.0.0" }, "scripts": { "start": "npm run test", @@ -15,15 +15,14 @@ "@babel/preset-env": "^7.15.0", "@babel/register": "^7.14.5", "@nuxeo/nuxeo-web-ui-ftest": "file:../../packages/nuxeo-web-ui-ftest", - "@wdio/cli": "7.20.5", - "@wdio/local-runner": "^7.20.5", - "@wdio/mocha-framework": "^7.2.0", - "@wdio/selenium-standalone-service": "7.2.0", - "@wdio/spec-reporter": "^7.2.0", - "@wdio/sync": "^7.2.0", + "@wdio/cli": "^8.16.11", + "@wdio/local-runner": "^8.16.11", + "@wdio/mocha-framework": "8.16.11", + "@wdio/selenium-standalone-service": "^8.15.0", + "@wdio/spec-reporter": "^8.16.9", "axe-core": "^4.1.2", - "chrome-launcher": "^0.14.0", + "chrome-launcher": "0.15.2", "node-fetch": "^2.6.1", - "wdio-chromedriver-service": "^7.0.0" + "wdio-chromedriver-service": "^8.1.1" } -} +} \ No newline at end of file diff --git a/plugin/a11y/test/a11y-reporter.js b/plugin/a11y/test/a11y-reporter.js index 9346cfbbc7..743a666216 100644 --- a/plugin/a11y/test/a11y-reporter.js +++ b/plugin/a11y/test/a11y-reporter.js @@ -2,31 +2,27 @@ import { runAxeCore } from './axe-reporter.js'; export function reportA11y(expectedViolations, expectedIncompleteViolations, setup) { let _report; - - const getReport = () => { + const getReport = async () => { if (_report) { return _report; } - browser.setTimeout({ script: 240000 }); - - setup(); - - browser.pause(3000); - _report = runAxeCore(); - + await setup(); + await browser.setTimeout({ script: 240000 }); + await browser.pause(3000); + _report = await runAxeCore(); return _report; }; context('Violations', () => { let report; - before(() => { - report = getReport(); + before(async () => { + report = await getReport(); }); Object.entries(expectedViolations).forEach(([violation, issues]) => { - it(`${violation}: ${issues} issue(s)`, () => { - expect(report.violations).toEqual( + it(`${violation}: ${issues} issue(s)`, async () => { + await expect(report.violations).toEqual( expect.arrayContaining([ { id: violation, @@ -41,13 +37,13 @@ export function reportA11y(expectedViolations, expectedIncompleteViolations, set context('Incomplete violations', () => { let report; - before(() => { - report = getReport(); + before(async () => { + report = await getReport(); }); Object.entries(expectedIncompleteViolations).forEach(([violation, issues]) => { - it(`${violation}: ${issues} issue(s)`, () => { - expect(report.incomplete).toEqual( + it(`${violation}: ${issues} issue(s)`, async () => { + await expect(report.incomplete).toEqual( expect.arrayContaining([ { id: violation, diff --git a/plugin/a11y/test/axe-reporter.js b/plugin/a11y/test/axe-reporter.js index 40d4fb27db..a5d91e6b87 100644 --- a/plugin/a11y/test/axe-reporter.js +++ b/plugin/a11y/test/axe-reporter.js @@ -1,35 +1,40 @@ // eslint-disable-next-line import/no-unresolved import { source } from 'axe-core'; -export function runAxeCore() { - // inject the axe-core lib - browser.execute(source); +class AxeCore { + async run() { + await browser.execute(source); + const options = { + runOnly: { + type: 'tag', + values: ['ACT', 'best-practice', 'wcag2a', 'wcag2aa'], + }, + }; + // run inside browser and get results + const results = await browser.executeAsync((opts, done) => { + // eslint-disable-next-line no-undef + axe + .run(opts) + .then((res) => done(res)) + .catch((err) => { + throw err; + }); + }, options); + return this.process(await results); + } - // https://github.com/dequelabs/axe-core/blob/develop/doc/API.md - const options = { - runOnly: { - type: 'tag', - values: ['ACT', 'best-practice', 'wcag2a', 'wcag2aa'], - }, - }; - // run inside browser and get results - const results = browser.executeAsync((opts, done) => { - // eslint-disable-next-line no-undef - axe - .run(opts) - .then((res) => done(res)) - .catch((err) => { - throw err; - }); - }, options); - - return { - results, - incomplete: results.incomplete.map((a) => { - return { id: a.id, issues: a.nodes.length }; - }), - violations: results.violations.map((a) => { - return { id: a.id, issues: a.nodes.length }; - }), - }; + process(results) { + return { + results, + incomplete: results.incomplete.map((a) => { + return { id: a.id, issues: a.nodes.length }; + }), + violations: results.violations.map((a) => { + return { id: a.id, issues: a.nodes.length }; + }), + }; + } +} +export async function runAxeCore() { + return new AxeCore().run(); } diff --git a/plugin/a11y/test/helpers/login.js b/plugin/a11y/test/helpers/login.js index 4ac00dc144..399bd805f7 100644 --- a/plugin/a11y/test/helpers/login.js +++ b/plugin/a11y/test/helpers/login.js @@ -1,13 +1,12 @@ import Login from '@nuxeo/nuxeo-web-ui-ftest/pages/login'; import UI from '@nuxeo/nuxeo-web-ui-ftest/pages/ui'; -const login = (username = 'Administrator', password = 'Administrator') => { - const logIn = Login.get(); - logIn.username = username; - logIn.password = password; - logIn.submit(); - const ui = UI.get(); - ui.waitForVisible('nuxeo-page'); +const login = async (username = 'Administrator', password = 'Administrator') => { + const logIn = await Login.get(); + await logIn.username(username); + await logIn.password(password); + await logIn.submit(); + const ui = await UI.get(); + await ui.waitForVisible('nuxeo-page'); }; - export default login; diff --git a/plugin/a11y/test/specs/browser.js b/plugin/a11y/test/specs/browser.js index e0cb442b8e..6c019a1c28 100644 --- a/plugin/a11y/test/specs/browser.js +++ b/plugin/a11y/test/specs/browser.js @@ -1,6 +1,6 @@ import '../imports'; -import UI from '@nuxeo/nuxeo-web-ui-ftest/pages/ui'; import documentService from '@nuxeo/nuxeo-web-ui-ftest/features/step_definitions/support/services/documentService'; +import UI from '@nuxeo/nuxeo-web-ui-ftest/pages/ui'; import login from '../helpers/login'; import { reportA11y } from '../a11y-reporter.js'; @@ -34,10 +34,16 @@ describe('Nuxeo Browser', () => { after(async () => documentService.reset()); - reportA11y(EXPECTED_VIOLATIONS, EXPECTED_INCOMPLETE_VIOLATIONS, () => { - login(); - const ui = UI.get(); - ui.browser.browseTo(doc.path); - ui.browser.currentPage.waitForDisplayed(); + reportA11y(EXPECTED_VIOLATIONS, EXPECTED_INCOMPLETE_VIOLATIONS, async () => { + try { + await login(); + const ui = await UI.get(); + await ui.waitForVisible('nuxeo-page'); + await ui.browser.browseTo(doc.path); + const page = await ui.browser.currentPage; + await page.waitForDisplayed(); + } catch (error) { + console.warn(error); + } }); }); diff --git a/plugin/a11y/test/specs/home.js b/plugin/a11y/test/specs/home.js index 34547a3c15..4bbd6ddf11 100644 --- a/plugin/a11y/test/specs/home.js +++ b/plugin/a11y/test/specs/home.js @@ -1,6 +1,6 @@ import '../imports'; -import UI from '@nuxeo/nuxeo-web-ui-ftest/pages/ui'; import documentService from '@nuxeo/nuxeo-web-ui-ftest/features/step_definitions/support/services/documentService'; +import UI from '@nuxeo/nuxeo-web-ui-ftest/pages/ui'; import login from '../helpers/login'; import { reportA11y } from '../a11y-reporter.js'; @@ -18,6 +18,7 @@ const EXPECTED_VIOLATIONS = { const EXPECTED_INCOMPLETE_VIOLATIONS = { 'aria-allowed-role': 5, 'color-contrast-enhanced': 2, + 'aria-required-children': 1, }; describe('Nuxeo Home', () => { @@ -28,9 +29,10 @@ describe('Nuxeo Home', () => { await documentService.create(parent.path, child); }); - reportA11y(EXPECTED_VIOLATIONS, EXPECTED_INCOMPLETE_VIOLATIONS, () => { - login(); - const ui = UI.get(); - ui.home.el.$('nuxeo-card[icon="nuxeo:edit"]').waitForDisplayed(); + reportA11y(EXPECTED_VIOLATIONS, EXPECTED_INCOMPLETE_VIOLATIONS, async () => { + await login(); + const ui = await UI.get(); + const ele = await ui.home.el.$('nuxeo-card[icon="nuxeo:edit"]'); + await ele.waitForDisplayed(); }); }); diff --git a/plugin/a11y/wdio.conf.js b/plugin/a11y/wdio.conf.js index d3d5ed6348..32ac676978 100644 --- a/plugin/a11y/wdio.conf.js +++ b/plugin/a11y/wdio.conf.js @@ -24,6 +24,7 @@ const capability = { maxInstances: 1, browserName: 'chrome', acceptInsecureCerts: true, + browserVersion: 'stable', }; const options = { args: ['--no-sandbox'], @@ -149,17 +150,7 @@ exports.config = { // Services take over a specific job you don't want to take care of. They enhance // your test setup with almost no effort. Unlike plugins, they don't add new // commands. Instead, they hook themselves up into the test process. - services: [ - [ - 'selenium-standalone', - { - installArgs: { drivers }, - args: { drivers }, - }, - ], - [CompatService], - [ShadowService], - ], + services: [[CompatService], [ShadowService]], // Framework you want to run your specs with. // The following are supported: Mocha, Jasmine, and Cucumber diff --git a/plugin/web-ui/addon/build.xml b/plugin/web-ui/addon/build.xml index 28a398b8ed..bbcda664f9 100644 --- a/plugin/web-ui/addon/build.xml +++ b/plugin/web-ui/addon/build.xml @@ -34,8 +34,6 @@ limitations under the License. - -