From 4e67a8d9b06abb2707c13d227014f0ad41f13b0c Mon Sep 17 00:00:00 2001 From: Akash Rathod <41251473+akashrathod28@users.noreply.github.com> Date: Fri, 26 Jul 2024 13:07:32 +0200 Subject: [PATCH] [ACS-8153] delete protractor e2e configuration and files (#3885) * [ACS-8153] delete protractor e2e configuration and files * [ACS-8153] util fix * [ACS-8153] pr fix * [ACS-81532] remove e2e package.json * [ACS-81532] remove chrome configuration * package-lock file --- .github/actions/adf-linking/action.yml | 1 - .github/actions/before-e2e/action.yml | 21 - .github/actions/run-e2e/action.yml | 43 -- .github/actions/setup/action.yml | 3 - .github/workflows/pull-request.yml | 2 - e2e/protractor/.eslintrc.json | 26 - .../e2e-config/utils/build-number.js | 10 - .../e2e-config/utils/upload-output.js | 69 --- e2e/protractor/project.json | 23 - e2e/protractor/protractor.excludes.json | 44 -- .../resources/test-files/file-docx.docx | Bin 9926 -> 0 bytes .../resources/test-files/file-jpg.jpg | Bin 22812 -> 0 bytes .../resources/test-files/file-pdf.pdf | Bin 3028 -> 0 bytes .../resources/test-files/file-xlsx.xlsx | Bin 97629 -> 0 bytes .../resources/test-files/file2-docx.docx | Bin 11523 -> 0 bytes .../resources/test-files/file2-xlsx.xlsx | Bin 97629 -> 0 bytes .../resources/test-files/file_unsupported.3DS | 1 - .../resources/test-files/protected.pdf | Bin 18052 -> 0 bytes e2e/protractor/smartrunner-factory.js | 14 - .../upload-download/upload-file.test.ts | 98 ---- e2e/protractor/tsconfig.e2e.adf.json | 15 - e2e/protractor/tsconfig.e2e.json | 16 - package-lock.json | 492 ++++-------------- package.json | 6 - .../src/api/file-actions.ts | 2 +- .../src/page-objects/playwright-base.ts | 2 +- .../src/utils}/api.ts | 6 +- .../aca-playwright-shared/src/utils/index.ts | 2 + .../src/utils}/logger.ts | 18 +- projects/aca-testing-shared/package.json | 13 - projects/aca-testing-shared/project.json | 7 - .../src/components/breadcrumb/breadcrumb.ts | 40 -- .../src/components/component.ts | 60 --- .../src/components/components.ts | 35 -- .../src/components/data-table/data-table.ts | 251 --------- .../src/components/dialog/confirm-dialog.ts | 49 -- .../dialog/content-node-selector-dialog.ts | 70 --- .../dialog/create-edit-folder-dialog.ts | 83 --- .../src/components/dialog/generic-dialog.ts | 70 --- .../src/components/dialog/index.ts | 32 -- .../dialog/manage-versions-dialog.ts | 46 -- .../src/components/dialog/share-dialog.ts | 41 -- .../components/dialog/upload-files-dialog.ts | 39 -- .../dialog/upload-new-version-dialog.ts | 56 -- .../src/components/header/header.ts | 60 --- .../src/components/index.ts | 38 -- .../src/components/info-drawer/index.ts | 27 - .../info-drawer/info-drawer-comments-tab.ts | 115 ---- .../info-drawer-metadata-library.ts | 217 -------- .../src/components/info-drawer/info-drawer.ts | 97 ---- .../src/components/login/login.ts | 50 -- .../src/components/menu/menu.ts | 66 --- .../pageLayoutHeader/pageLayoutHeader.ts | 39 -- .../src/components/pagination/pagination.ts | 69 --- .../filters/autocomplete-chips-filter.ts | 58 --- .../search/filters/created-date-filter.ts | 0 .../components/search/filters/facet-filter.ts | 74 --- .../search/filters/facet-tabbed-filter.ts | 91 ---- .../search/filters/generic-filter.ts | 92 ---- .../search/filters/properties-filter.ts | 103 ---- .../src/components/search/index.ts | 31 -- .../src/components/search/search-filters.ts | 43 -- .../src/components/search/search-input.ts | 172 ------ .../search/search-sorting-picker.ts | 73 --- .../src/components/sidenav/sidenav.ts | 83 --- .../src/components/toolbar/toolbar.ts | 118 ----- .../src/components/viewer/viewer.ts | 68 --- projects/aca-testing-shared/src/configs.ts | 96 ---- projects/aca-testing-shared/src/index.ts | 28 - .../src/pages/browsing-page.ts | 95 ---- .../aca-testing-shared/src/pages/index.ts | 27 - .../src/pages/login-page.ts | 65 --- projects/aca-testing-shared/src/pages/page.ts | 113 ---- .../src/pages/search-results-page.ts | 36 -- .../src/utilities/admin-actions.ts | 52 -- .../src/utilities/browser-actions.ts | 84 --- .../src/utilities/browser-visibility.ts | 80 --- .../aca-testing-shared/src/utilities/index.ts | 34 -- .../apis/favorites/favorites-api.ts | 156 ------ .../src/utilities/repo-client/apis/index.ts | 34 -- .../apis/nodes/node-content-tree.ts | 96 ---- .../repo-client/apis/nodes/nodes-api.ts | 449 ---------------- .../apis/people/people-api-models.ts | 52 -- .../repo-client/apis/queries/queries-api.ts | 70 --- .../utilities/repo-client/apis/repo-api.ts | 54 -- .../repo-client/apis/search/search-api.ts | 122 ----- .../apis/shared-links/shared-links-api.ts | 94 ---- .../repo-client/apis/sites/sites-api.ts | 150 ------ .../repo-client/apis/upload/upload-api.ts | 74 --- .../src/utilities/repo-client/repo-client.ts | 81 --- .../src/utilities/test-element.ts | 155 ------ .../src/utilities/user-actions.ts | 169 ------ .../aca-testing-shared/src/utilities/utils.ts | 184 ------- projects/aca-testing-shared/tsconfig.lib.json | 25 - protractor.conf.js | 225 -------- scripts/webdriver-update-newest/README.md | 37 -- .../chrome_xml_schema.js | 181 ------- .../update-to-newest-webdriver.sh | 72 --- .../webdriver-update-newest/update_schema.js | 304 ----------- 99 files changed, 131 insertions(+), 6953 deletions(-) delete mode 100644 .github/actions/run-e2e/action.yml delete mode 100644 e2e/protractor/.eslintrc.json delete mode 100644 e2e/protractor/e2e-config/utils/build-number.js delete mode 100644 e2e/protractor/e2e-config/utils/upload-output.js delete mode 100644 e2e/protractor/project.json delete mode 100644 e2e/protractor/protractor.excludes.json delete mode 100644 e2e/protractor/resources/test-files/file-docx.docx delete mode 100644 e2e/protractor/resources/test-files/file-jpg.jpg delete mode 100644 e2e/protractor/resources/test-files/file-pdf.pdf delete mode 100644 e2e/protractor/resources/test-files/file-xlsx.xlsx delete mode 100644 e2e/protractor/resources/test-files/file2-docx.docx delete mode 100644 e2e/protractor/resources/test-files/file2-xlsx.xlsx delete mode 100755 e2e/protractor/resources/test-files/file_unsupported.3DS delete mode 100644 e2e/protractor/resources/test-files/protected.pdf delete mode 100644 e2e/protractor/smartrunner-factory.js delete mode 100755 e2e/protractor/suites/actions/upload-download/upload-file.test.ts delete mode 100644 e2e/protractor/tsconfig.e2e.adf.json delete mode 100755 e2e/protractor/tsconfig.e2e.json rename projects/{aca-testing-shared/src/utilities => aca-playwright-shared/src/utils}/api.ts (86%) rename projects/{aca-testing-shared/src/utilities => aca-playwright-shared/src/utils}/logger.ts (86%) delete mode 100644 projects/aca-testing-shared/package.json delete mode 100644 projects/aca-testing-shared/project.json delete mode 100755 projects/aca-testing-shared/src/components/breadcrumb/breadcrumb.ts delete mode 100755 projects/aca-testing-shared/src/components/component.ts delete mode 100755 projects/aca-testing-shared/src/components/components.ts delete mode 100755 projects/aca-testing-shared/src/components/data-table/data-table.ts delete mode 100755 projects/aca-testing-shared/src/components/dialog/confirm-dialog.ts delete mode 100755 projects/aca-testing-shared/src/components/dialog/content-node-selector-dialog.ts delete mode 100755 projects/aca-testing-shared/src/components/dialog/create-edit-folder-dialog.ts delete mode 100644 projects/aca-testing-shared/src/components/dialog/generic-dialog.ts delete mode 100644 projects/aca-testing-shared/src/components/dialog/index.ts delete mode 100755 projects/aca-testing-shared/src/components/dialog/manage-versions-dialog.ts delete mode 100755 projects/aca-testing-shared/src/components/dialog/share-dialog.ts delete mode 100644 projects/aca-testing-shared/src/components/dialog/upload-files-dialog.ts delete mode 100755 projects/aca-testing-shared/src/components/dialog/upload-new-version-dialog.ts delete mode 100755 projects/aca-testing-shared/src/components/header/header.ts delete mode 100644 projects/aca-testing-shared/src/components/index.ts delete mode 100644 projects/aca-testing-shared/src/components/info-drawer/index.ts delete mode 100755 projects/aca-testing-shared/src/components/info-drawer/info-drawer-comments-tab.ts delete mode 100755 projects/aca-testing-shared/src/components/info-drawer/info-drawer-metadata-library.ts delete mode 100755 projects/aca-testing-shared/src/components/info-drawer/info-drawer.ts delete mode 100755 projects/aca-testing-shared/src/components/login/login.ts delete mode 100755 projects/aca-testing-shared/src/components/menu/menu.ts delete mode 100644 projects/aca-testing-shared/src/components/pageLayoutHeader/pageLayoutHeader.ts delete mode 100755 projects/aca-testing-shared/src/components/pagination/pagination.ts delete mode 100644 projects/aca-testing-shared/src/components/search/filters/autocomplete-chips-filter.ts delete mode 100755 projects/aca-testing-shared/src/components/search/filters/created-date-filter.ts delete mode 100755 projects/aca-testing-shared/src/components/search/filters/facet-filter.ts delete mode 100644 projects/aca-testing-shared/src/components/search/filters/facet-tabbed-filter.ts delete mode 100755 projects/aca-testing-shared/src/components/search/filters/generic-filter.ts delete mode 100644 projects/aca-testing-shared/src/components/search/filters/properties-filter.ts delete mode 100644 projects/aca-testing-shared/src/components/search/index.ts delete mode 100755 projects/aca-testing-shared/src/components/search/search-filters.ts delete mode 100755 projects/aca-testing-shared/src/components/search/search-input.ts delete mode 100755 projects/aca-testing-shared/src/components/search/search-sorting-picker.ts delete mode 100755 projects/aca-testing-shared/src/components/sidenav/sidenav.ts delete mode 100755 projects/aca-testing-shared/src/components/toolbar/toolbar.ts delete mode 100755 projects/aca-testing-shared/src/components/viewer/viewer.ts delete mode 100755 projects/aca-testing-shared/src/configs.ts delete mode 100644 projects/aca-testing-shared/src/index.ts delete mode 100755 projects/aca-testing-shared/src/pages/browsing-page.ts delete mode 100755 projects/aca-testing-shared/src/pages/index.ts delete mode 100755 projects/aca-testing-shared/src/pages/login-page.ts delete mode 100755 projects/aca-testing-shared/src/pages/page.ts delete mode 100755 projects/aca-testing-shared/src/pages/search-results-page.ts delete mode 100755 projects/aca-testing-shared/src/utilities/admin-actions.ts delete mode 100644 projects/aca-testing-shared/src/utilities/browser-actions.ts delete mode 100644 projects/aca-testing-shared/src/utilities/browser-visibility.ts delete mode 100644 projects/aca-testing-shared/src/utilities/index.ts delete mode 100755 projects/aca-testing-shared/src/utilities/repo-client/apis/favorites/favorites-api.ts delete mode 100644 projects/aca-testing-shared/src/utilities/repo-client/apis/index.ts delete mode 100755 projects/aca-testing-shared/src/utilities/repo-client/apis/nodes/node-content-tree.ts delete mode 100755 projects/aca-testing-shared/src/utilities/repo-client/apis/nodes/nodes-api.ts delete mode 100755 projects/aca-testing-shared/src/utilities/repo-client/apis/people/people-api-models.ts delete mode 100755 projects/aca-testing-shared/src/utilities/repo-client/apis/queries/queries-api.ts delete mode 100644 projects/aca-testing-shared/src/utilities/repo-client/apis/repo-api.ts delete mode 100755 projects/aca-testing-shared/src/utilities/repo-client/apis/search/search-api.ts delete mode 100755 projects/aca-testing-shared/src/utilities/repo-client/apis/shared-links/shared-links-api.ts delete mode 100755 projects/aca-testing-shared/src/utilities/repo-client/apis/sites/sites-api.ts delete mode 100644 projects/aca-testing-shared/src/utilities/repo-client/apis/upload/upload-api.ts delete mode 100755 projects/aca-testing-shared/src/utilities/repo-client/repo-client.ts delete mode 100644 projects/aca-testing-shared/src/utilities/test-element.ts delete mode 100644 projects/aca-testing-shared/src/utilities/user-actions.ts delete mode 100644 projects/aca-testing-shared/src/utilities/utils.ts delete mode 100644 projects/aca-testing-shared/tsconfig.lib.json delete mode 100755 protractor.conf.js delete mode 100644 scripts/webdriver-update-newest/README.md delete mode 100644 scripts/webdriver-update-newest/chrome_xml_schema.js delete mode 100755 scripts/webdriver-update-newest/update-to-newest-webdriver.sh delete mode 100644 scripts/webdriver-update-newest/update_schema.js diff --git a/.github/actions/adf-linking/action.yml b/.github/actions/adf-linking/action.yml index 9c86dcd5c6..c5d4e99e72 100644 --- a/.github/actions/adf-linking/action.yml +++ b/.github/actions/adf-linking/action.yml @@ -11,7 +11,6 @@ runs: if [[ $COMMIT_MESSAGE == *"[link-adf:"* ]]; then echo "BUILD_OPTS=--configuration=adf,e2e" >> $GITHUB_ENV echo "TEST_OPTS=--configuration=adfprod" >> $GITHUB_ENV - echo "E2E_PROTRACTOR_OPTS=--with-local-adf" >> $GITHUB_ENV echo "E2E_TSCONFIG=tsconfig.e2e.adf.json" >> $GITHUB_ENV BRANCH=`echo $COMMIT_MESSAGE | grep -o "\[link-adf\:[^]]*\]" | sed -e 's#\[link-adf:##g' | sed -e 's#\]##g'` diff --git a/.github/actions/before-e2e/action.yml b/.github/actions/before-e2e/action.yml index f7049dc1cf..086fe854b4 100644 --- a/.github/actions/before-e2e/action.yml +++ b/.github/actions/before-e2e/action.yml @@ -1,30 +1,9 @@ name: "Before e2e" description: "Before e2e" -inputs: - e2e-protractor: - description: 'is e2e run with protractor' - required: false - type: boolean - default: false - runs: using: "composite" steps: - name: Check content UP shell: bash run: ./node_modules/@alfresco/adf-cli/bin/adf-cli check-cs-env --host $BASE_URL -u $ADMIN_EMAIL -p $ADMIN_PASSWORD || exit 1 - - - name: Install google chrome v114 - shell: bash - run: | - wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb - sudo apt install ./google-chrome-stable_current_amd64.deb - sudo ln -s /usr/bin/google-chrome /usr/bin/chrome - chrome --version - - - name: Update webdriver-manager - if: ${{ inputs.e2e-protractor == 'true' }} - shell: bash - run: | - npm run update-webdriver diff --git a/.github/actions/run-e2e/action.yml b/.github/actions/run-e2e/action.yml deleted file mode 100644 index 6f034f6b99..0000000000 --- a/.github/actions/run-e2e/action.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: "Run e2e" -description: "Run e2e" - -inputs: - options: - description: 'Options' - required: true - type: string - test-runner: - description: 'Test runner' - required: false - type: string - default: 'protractor' - artifact-name: - description: Name of the artifact cache - required: true - type: string - -runs: - using: "composite" - steps: - - name: Setup and run with options - shell: bash - run: | - ./node_modules/.bin/tsc -p "./e2e/protractor/$E2E_TSCONFIG" || exit 1; - npm start > /dev/null &\ - - if [ ${{ inputs.test-runner }} == "playwright" ]; then - echo "Running playwright tests with options ${{ inputs.options }}" - sleep 90 - npx nx run ${{ inputs.options }}-e2e:e2e - else - echo "Running protractor tests with options ${{ inputs.options }}" - echo "./node_modules/.bin/protractor \"./protractor.conf.js\" ${{ inputs.options }} || exit 1" - ./node_modules/.bin/protractor "./protractor.conf.js" ${{ inputs.options }} $E2E_PROTRACTOR_OPTS || exit 1 - fi - - - name: Upload E2Es results - if: ${{ always() }} - uses: actions/upload-artifact@v3 - with: - name: ${{ inputs.artifact-name }} - path: e2e-output/ diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index facd300f29..6f78b9a684 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -9,11 +9,8 @@ runs: run: | echo "BUILD_OPTS=--configuration=production,e2e" >> $GITHUB_ENV echo "TEST_OPTS=" >> $GITHUB_ENV - echo "E2E_PROTRACTOR_OPTS=" >> $GITHUB_ENV echo "E2E_TSCONFIG=tsconfig.e2e.json" >> $GITHUB_ENV echo "GIT_HASH=$(git rev-parse HEAD)" >> $GITHUB_ENV - echo "SMART_RUNNER_DIRECTORY=.protractor-smartrunner" >> $GITHUB_ENV - echo "BASE_HASH=.protractor-smartrunner" >> $GITHUB_ENV echo "HEAD_HASH=HEAD" >> $GITHUB_ENV - uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@v1.35.0 diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 69f9ecb2be..a1316d0056 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -151,8 +151,6 @@ jobs: - name: Before e2e uses: ./.github/actions/before-e2e - with: - e2e-protractor: false - name: before playwright shell: bash diff --git a/e2e/protractor/.eslintrc.json b/e2e/protractor/.eslintrc.json deleted file mode 100644 index 6ae84700d0..0000000000 --- a/e2e/protractor/.eslintrc.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "extends": "../../.eslintrc.json", - "ignorePatterns": [ - "!**/*" - ], - "overrides": [ - { - "files": [ - "*.ts" - ], - "parserOptions": { - "project": [ - "e2e/protractor/tsconfig.e2e.json" - ], - "createDefaultProgram": true - }, - "plugins": [ - "rxjs", - "unicorn" - ], - "rules": { - "@typescript-eslint/no-floating-promises": "off" - } - } - ] -} diff --git a/e2e/protractor/e2e-config/utils/build-number.js b/e2e/protractor/e2e-config/utils/build-number.js deleted file mode 100644 index b4e7f31ffe..0000000000 --- a/e2e/protractor/e2e-config/utils/build-number.js +++ /dev/null @@ -1,10 +0,0 @@ -const buildNumber = () => { - let buildNumber = process.env.GH_BUILD_NUMBER; - if (!buildNumber) { - process.env.GH_BUILD_NUMBER = Date.now(); - } - - return process.env.GH_BUILD_NUMBER; -} - -module.exports = buildNumber; diff --git a/e2e/protractor/e2e-config/utils/upload-output.js b/e2e/protractor/e2e-config/utils/upload-output.js deleted file mode 100644 index 532d7b7f9a..0000000000 --- a/e2e/protractor/e2e-config/utils/upload-output.js +++ /dev/null @@ -1,69 +0,0 @@ -const path = require('node:path'); -const fs = require('node:fs'); -const child_process = require('node:child_process'); -const { AlfrescoApi, NodesApi, UploadApi } = require('@alfresco/js-api'); -const buildNumber = require('./build-number'); -const outputDir = path.resolve(__dirname, '../../../e2e-output/'); - -async function saveScreenshots(retryCount) { - const folderName = process.env.GITHUB_JOB; - console.log(`Start uploading report in ${folderName}`); - - const alfrescoJsApi = new AlfrescoApi({ - provider: 'ECM', - hostEcm: process.env.SCREENSHOT_URL - }); - - const nodesApi = new NodesApi(alfrescoJsApi); - const uploadApi = new UploadApi(alfrescoJsApi); - - await alfrescoJsApi.login(process.env.SCREENSHOT_USERNAME, process.env.SCREENSHOT_PASSWORD); - - let folderNode; - - try { - folderNode = await nodesApi.createNode( - '-my-', - { - name: `retry-${retryCount}`, - relativePath: `Builds/ACA-${buildNumber()}/${folderName}/`, - nodeType: 'cm:folder' - }, - {}, - { - overwrite: true - } - ); - } catch (error) { - folderNode = await nodesApi.createNode( - '-my-', - { - relativePath: `Builds/ACA-${buildNumber()}/${folderName}/retry-${retryCount}`, - nodeType: 'cm:folder' - }, - {}, - { - overwrite: true - } - ); - } - - fs.renameSync(outputDir, path.join(`${outputDir}-${folderName}-${retryCount}/`)); - - child_process.execSync(` tar -czvf ../e2e-result-${folderName}-${retryCount}.tar .`, { - cwd: `${outputDir}-${folderName}-${retryCount}/` - }); - - const pathFile = path.join(outputDir, `../e2e-result-${folderName}-${retryCount}.tar`); - const file = fs.createReadStream(pathFile); - - await uploadApi.uploadFile(file, '', folderNode.entry.id, null, { - name: `e2e-result-${folderName}-${retryCount}.tar`, - nodeType: 'cm:content', - autoRename: true - }); -} - -module.exports = { - saveScreenshots: saveScreenshots -}; diff --git a/e2e/protractor/project.json b/e2e/protractor/project.json deleted file mode 100644 index 5bd863cda1..0000000000 --- a/e2e/protractor/project.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "app-e2e", - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "e2e", - "projectType": "application", - "targets": { - "e2e": { - "executor": "@angular-devkit/build-angular:protractor", - "options": { - "protractorConfig": "./protractor.conf.js", - "devServerTarget": "content-ce:serve" - }, - "configurations": { - "production": { - "devServerTarget": "content-ce:serve:production" - } - } - }, - "lint": { - "executor": "@angular-eslint/builder:lint" - } - } -} diff --git a/e2e/protractor/protractor.excludes.json b/e2e/protractor/protractor.excludes.json deleted file mode 100644 index 3ec3b6e439..0000000000 --- a/e2e/protractor/protractor.excludes.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "C261153": "https://alfresco.atlassian.net/browse/AAE-7517", - "C306959": "https://alfresco.atlassian.net/browse/ACA-4620", - "C213134": "temp, see https://alfresco.atlassian.net/browse/ACS-5189", - "C286252": "temp, see https://alfresco.atlassian.net/browse/ACS-5189", - "C284666": "temp, see https://alfresco.atlassian.net/browse/ACS-5189", - "C279186": "will be fixed after protractor to playwright migration, see https://alfresco.atlassian.net/browse/ACS-5007", - "C279211": "will be fixed after protractor to playwright migration, see https://alfresco.atlassian.net/browse/ACS-5007", - "C279212": "will be fixed after protractor to playwright migration, see https://alfresco.atlassian.net/browse/ACS-5007", - "C279213": "will be fixed after protractor to playwright migration, see https://alfresco.atlassian.net/browse/ACS-5007", - "C279214": "will be fixed after protractor to playwright migration, see https://alfresco.atlassian.net/browse/ACS-5007", - "C279215": "will be fixed after protractor to playwright migration, see https://alfresco.atlassian.net/browse/ACS-5007", - "C279216": "will be fixed after protractor to playwright migration, see https://alfresco.atlassian.net/browse/ACS-5007", - "C279217": "will be fixed after protractor to playwright migration, see https://alfresco.atlassian.net/browse/ACS-5007", - "C279219": "will be fixed after protractor to playwright migration, see https://alfresco.atlassian.net/browse/ACS-5007", - "C279220": "will be fixed after protractor to playwright migration, see https://alfresco.atlassian.net/browse/ACS-5007", - "C279221": "will be fixed after protractor to playwright migration, see https://alfresco.atlassian.net/browse/ACS-5007", - "C325006": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C280025": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C289880": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C289881": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C297659": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C280077": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C289903": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C277224": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C289893": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C290014": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C290017": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C279162": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C290012": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C289988": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C289991": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C279177": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C306965": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C217095": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C280116": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C280081": "will be fixed after protractor to playwright migration, see https://alfresco.atlassiana.net/browse/ACS-5007", - "C213097": "https://alfresco.atlassian.net/browse/ACS-5479", - "C269007" : "date test fail migrate to playwright https://alfresco.atlassian.net/browse/ACS-6185 ", - "C307106" : "date test fail migrate to playwright https://alfresco.atlassian.net/browse/ACS-6185 ", - "C269003" : "date test fail migrate to playwright https://alfresco.atlassian.net/browse/ACS-6185 ", - "C290018" : "https://alfresco.atlassian.net/browse/ACA-4731", - "C277727" : "https://alfresco.atlassian.net/browse/ACS-6672" -} diff --git a/e2e/protractor/resources/test-files/file-docx.docx b/e2e/protractor/resources/test-files/file-docx.docx deleted file mode 100644 index 7d4e30425ebc49470fb19ce92e89c4afb7202a3a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9926 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 diff --git a/e2e/protractor/resources/test-files/file-jpg.jpg b/e2e/protractor/resources/test-files/file-jpg.jpg deleted file mode 100644 index eb6bf4a4570fa8112b945e44f6af249a47450b41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22812 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 S>NZV0@_bPEqs!}&ZT$n`rwj1_ diff --git a/e2e/protractor/resources/test-files/file-xlsx.xlsx b/e2e/protractor/resources/test-files/file-xlsx.xlsx deleted file mode 100644 index 3039a7cdc8579121f821af3dbb78590f00ba19f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 97629 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 diff --git a/e2e/protractor/resources/test-files/file2-docx.docx b/e2e/protractor/resources/test-files/file2-docx.docx deleted file mode 100644 index c0d0614a84fc9b0ab28ab8964f91a7c74181a5f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11523 zcmeHN^+R0AvL4*sT>>Gvy9L+a?(VL^3GQwgEVz4s1a}R=Avk1kLU6Y?$$fh_o89;R zfqTynJ#)IxSEr|^s;lbjQj&v$#saP9+C#z9y_ogmDM2<5$!0c*{@dFH3otw7lC#N7>%CP2Y7;MZ;}nHx#<_? zHyH!W2%c}Gu&jym zvaesYuR^7-QajNqHo_618oa|qO0J*h^mCA=#5Y@Toz}8Ul@Bp`j~%)1yEl`Y;+w9N z;Ib6#N^%@Wh%cO>q!|bI&5g{BLz#YPfU?-rxGcKHS543BV{IXW!V>ZNxq1=x``blE zab}3b&&$C4Dy_VgoTnFX#jy}=0urDl5;WSxbwU9DjzS2Iyl{==$!Hr^Vg7Pt2H^(* zN!t~KL@TH~ugmf6FN;}Gg`b_zA*>5P!UL-{c2%FP*8!}1(*gRK(sP#Ma2NLPUXl!L zFWuQ+LjeF!Pf!4*znCOxB4P6pSkDx|7Ka2jNkbQNJ6C3=AMJll@jux9e);K@N!>QR zEXXg9f**n>+m#o)@e34~O(&M{7vSJ^W#qAzzSzt^J_vmI0;#`eEHyecojl>~nkDJJ zo}zzDn5K>r)s8TCW6-O6*Y+Ba8roLG`g+dkD{|)crNzU@Ga1^E;Am}}sBuEr#OsKR zu`aAFI`PY`5+rL%+VL4vs)m9bXZ88341e}_Z&_#OY@~I4;K~IhI>Ja=J`?yOS_s#r zvoj{d_pH|I_o?kCe_)HXp}k-rv}0kW&Pp_?L?k?Jo80#<=q%}v3}rybLx^O)^R>{! z)Op;A+9nX@I-<~iZ@A$|l%+3n26jw;w~slq2IX_`Vz7d(hZq14;pymN#{4fMF>^F^ zw+DN#A8zXpgMk41F0h>c?5i?q6s$1dy*u0aK`LCzfG~Ex z(ODxcb1-4la_mx_;W{43wKU!xMQ}S-e1${TB#%G@Hbs1^RcM)`3P1^$!I{ZW< zT>}HVoCzBRxtWVM;`ux(6RhElDQ0}c9Ogpr=%rWPP<%qF6v9qVF`xE$WVJ|i&0vyQ4mW5wt0zMxPP^1cCwGJn?^ z0dkE`)8HNT9U=gL0ak{eTJx*E6sGAqX0l)puF)Lwldr0ZB^A@sm8E%9-LlZy%L;{pN%9lT4Ra#J-m3ru)UYp!Kj7xN-d!mc{P zNV?Bi@&#Q;)WpnL`{^q>kUr^q*g+R(Bav)0)U}z*h4$#Ef!0=L~u93TD%gpfhA<71Rjv^r0KH)8{Xy}GlGxW8J<@~Tycl9ypcoVMy!G>O{;b%dH>~#LgYiK;^=)r8r32PI zZq`oDwTkLtP!kPza<@`X<0Ct`*Q2%i7EB{TI_K?DSW0_5Hk8ZusOHID2XX{jqt%ix zbR{|9t8-D19)EMK3rw~W_S&$q3^zu{Z5$1 zBGUvx3i4UETu*3ED>1eR3a=8Z!VSzftd1yC?(Ei}iXH`VnkCs1`1Nv(_OR+5M!d5N z!fL#W3CV@-n?t*Y&1^U_>ln0;ds?!eBo`#rU&VPrp2hQ^>5tGj>f%*>SF)Ep{FcWg zVWhD(ht}j+K1l~%*DQ56*Ch<$YyUBgkJkeIsm8Kyz|4{NaQR4pZ@dyWVXl&vmB`(g zu4#Sdtxhq;!Xqqw7Gy_&?Gv*^LeHHEudW84*(ubLdrV;ONbWejR$5{4;r9^MpvH%+ z0TNqTXK|6SSk3b2P?l^57Z&s8m}>ZlA5a(N}6M!koB+&9x2tG=FqZ9|C&0Koaf0^F?3?ai5gwyZyP&2QRrj#yH}otpce z_=hC-5hO|QaQ$&8jL`XgO3uVbah`DF-zzN!5IWSID%Hy9s=QyQI0~xSC%)Vd^#{IJ zV@$n9d>H@c-EJD+ouF0(N!E6D{je6FUB_(DLd5PS9#SY^?bUduj+WTB1M#XS&9h;R zzj=eA%n8$I0Bh>>xwvA-`Lbr4%-piwQR}^k`PunkhAUuG8g{r zxtM}kID%V<_9zrDgz)#|))6seIT#|w8XF-4^E;CwauXW_`^aibAzpn2^qBoHg^=K& z+BsW0gD;HNL;%(34-U;sdvl2Xuz`ML3}bGzrbO+rIzA%}&?8~dZTzzqjm99k`+3~s z%tMdXkJcL~FNnBskBMe41{79$h?KbOnD*CJ_uS?f+aSz)FJOF+dbYiL2Z)sVtk`s3 z9=yg)q$L;oT+OpV1X#;>-i54AYpyAoTWbCh7sRi34loLe#(9+hEHsPo>vDGzK*zR) zcpbeyrO>oF8cNNGBx5+C*4P%Wij2b=-1hnw6kQTOIowV|bLG$bG2m%)bsV*vo(Ex6 zZM^g8>rr@aekW&wl z8j!BlVGG6dX(_`U+hFT<34YejL@Ifu*;rYRHz2c%%QRrV3^5?Zw2=Mr+GCJ*^OS?p z-b$Q-^NJvZIGl@b(4^LB?q+roI6pLyPtVr}ra@5?8b#ym*JkxQ^H?u?W{ zH`9xcQ=sx_6MolC(c18Lw_hvFE1F^uIsdG+>9@4s#rn!%E{-77-*@g1pK!gwk?b*^ z@C3CjSud4k%|Cr(JJTUNIkCv16;l@#B%nsJ_N{1=pgsBj@1OUf!4E z==7X~@RT|+PUB4=hrV{uln5H`SRXnL+$l$pG1KRsP{>SHOg%qQbvOJC?7o?p5T)%( zu}BrB4ML-|?6wQoHXOC4xhw+!MC>dnTK!hzX@9MesYTvLUj>*dYuE}z-Bu?)<3{8U z`R{?s_R2cO^{POx&D9W_ms*B*wg(sT9A?NCR1^N=`0~9j+Z0I{sM4g*?62}EI6=)g z%f-xI6>>{6c8V1CspP5soM{o6l1CiMK(-7CnfXIK-uk|rJkyDCZAb5+LF-YX9ty-T zXTA718^GM-qw)7Y_e?t_<-KTCIn_cN3TcU#ipq z#ol^)MwjvA_q+!6(-i!UpiKJiOb@cdKq#t(hDuGw*xqAUaYmBxGu096`?$CH?09ii zwr@yposiM-_lWJi^hzVd@MNFuUqKTS$1qGFiD+A;qEB~n+3F8ZRyvvs$cuFIijz#B zBOqogNCYMLr7qndS~RxNZ>J`*kKD=URm(T*1QKJ+&Cj-0A6_YO96tZ}4B0`*>QcaS zfP5zOwkgNA{=L@a|4^u5?+D^TeiSl#>OS82=zmo-P!#_B zNPNH{Y-gOFA2fsbC4t^b6y8ik*S>2`Z^8I!1omg2Nt5LDwyY&{ci)F{yM05Q8 zmVV?tdJ0xJCwgo#*f<+Jw!$1ff|(#0Giiwztb;6(`8{OTealDK%u-Q-i8=_3O#>|{ zCau(*q@7veEmYsv>oMI2S-AcBl#CI1;j48i8%<50Qc=3*62CniV){sCuTaD>efTa? zy4?>-Iur1C|~YNzy$^nKCzWb<1A0Aj1#RMpC?{{*6Za2c z1nnTi4>%SKlf(+K-G7VVXfJ#Z<)%m%Iy3RXR9{4t-}E3N>e2?=K0Mmn5#fn(CK~VWp}Ja zsX-gm2G^=3YO7pU0<(cy!@}`gNPxg`%vR%S$xGVgA+iJxu4c*qo3|pPnoO&)ESlXZ#|pQqb6Z`~Cq( z>W&iOYZJQz*Z5nFJ$qI(A;tlXd>hjxfG|02xI?+e$#RL=Jn#!w;2Tw_PT_~VMe1j1 z=UQw=4-m7L7Dj@I$xO~ISgkXAQ!?qi`doW1C8IR@8*ZVqjZ$BrSauXAz9_uEt$L?M z>~!YUV^|hOxr-~)Mu-dbJ{=z$R6McT(KlXe=49F&msV)JOR)Mv7V$txN7W5Go427c zgEMUh8HH^qcIK_?+Sj!$6FiMq??||%G+z1amQXm$a#TVf(2v5q$MtJ3MBJi2M<_Hf z+&qY%uUI$)>@YhCbp?E?U*a(|3_$*BmIhN{-h}8-09`nH;gU^bjoW|pNDMdm5dHB6 z>7Ps&`2-Vg5gho1f+ zEs~34OvT?J;JaA~0~k;vGn>~S_^lgDb=#vCFoV|Kpk4Q^JTy#hk_*1Dv;~giQ%@l_ zt9xiplPMll5Xq7|wQenHYfl$Idw1SmZ&cS1T0)`gIp(qD7u&<@r<#-NSo3_+qhZ7) z+Cf3%IdA>s^yIpxk6_71IwNU~6Q|w%B`FU7i8RWVka`o3=2CJoVb0RPhKdiVYJXk) zU`^~Gd(C4N0U^+n%X^)m`Wr!VIv#mJi03+xrFS%jM)rkXPQwiQElh0&>O z{%B(2#)u|y!Zb@X7HpiPkgAFJg}Y_;4pA(Xn%J=i)f-bHZrxbN;PcciSW7{tDlUT} z(ZMRHx2A_(?yt1F=j`6t-^+2uGmd=~pL9WE6Ag>Biy(4H5z0~7#pzPoRYO0d6?Urm ziV%)jN`iY?Ys~3q7K4*JXUj*$o5S>c>tctM_N&2OD@pPVuQ4k|WOCR|7e=IOPOy(f z@Eas7#Sv-pH8aHy{@z0(NyH{`ETnUcu}?GvCz1RsLm)@VYR8fL0DP}?*j(6vUU3eV zj0nl%_SgXS?x=akf*2Vu1q1m)pQnYs!!`LB60HYtLi_hk`~trdND9`3An+*mADZB4 zZle0jKAti)<^V~74tMO6+yS*wU0DpY09DIOXPhrzLL_9XQ}&|6wl0=1J2aA=d^LcF z-i8Zci{66Bz78Bp^QEQ%i6S0{5gu@-`UdF6k`}EO`W29Pm2P5aF&*5sN@#l2`iG{R z%HV3B=;fDfauq4j^;;m7ddWlhuG-P&D|iubBf2ji_70)LW`A4c%Z#(p!FKhs_{xab zSjBlPZxO$)YFI=0fgx$93dMJ_MfZK22^J-R(Pys-KcCX7C*$X6n&>)Mk!7zy#M}4z zIU`%i`MG&_Fc!UmdpIoIO#~L7#=}NZ1BkLCqZAYQ!bZofnMxq=i4$)cS0@uD5_1}NBf7xW%TEK_y>3Tes%$R{uLGSBSc$4gZhHT z)s9>Jc&}wCOemv2njq$SUcAJ13>ot7Qr<#I7u0M?kd(+OHVCP1AUq24Cz(vXUgVgE zTtjFVaV5a(@wRC5DtMyi6v6Ym`It?4CS&Csqku7zYd&Q!{|=)sNR&wW<6PW}W@Kgr zfihCp?rng9D4RAH`8MD(SXLJ6j;7{iCEGP=L4yv)9UWPf0!4USxgkxR`dipK2MB}p zz*|mjAmS5WDBOW1j%!zW(tdJOul8b6w+MZ>kAc3&h&l8LUZ5X-!D+I9w~x0IuzW%t zZ77J%*5YO-%w_G!H^%-0{dU${q2P)!Lk5)a(u}PJIC^5#nEZ_*Tzw?K)xG2}jz`Xg zATT~B0I7d==cZxg@S=Fbwf+Rkls(Om>ggYqR)Xw)&mXL``(UNT_*H359bJBUga2wR zc-_F4Z_=p3Pij>9UTo9PhQFvt+!`It9R?Fqg4|<(G>XER!Dn%zb5Le6lXOz{-u3j2m8xv}eW1#U=32Uel1XS51VqrE31VboJ51JJdzNFq!^-aC$8rdor%6&iPmsfX-)a1UE zf@T`bFogYj?|r{h7b@QiXm<*M)$r&JTc!D>d%9%}akL(7Wh-pPeKm-3bKS^3wH!nN$pUFpC_L9pI z4`$d=v(4I@qKcJhaUp)0Sj!QQq&nNLF*Gh*^XLfLTEQV{;a^ru3;|TsL$8$VYUjBl z-FMN#$%F&9WjgOKQ$}`a#*y;s8-^d3+GYA0w5Tatg)@CS@9wu(sOV(VsO8IJa$n_m zvECfccRn4a528ujFnD2Dztr%R1~m-VGiZ_(Pg5G4rr zKa-m|Q}eQOoQ^(v_XLXGgyOrKIR`5ap}%_$j!C}oM&*lfq;5W8J)kh3aAfq9*PSSp z2^%Lh?$a#UquHsQi_=7htF=w-MUL5m-yP}r>b?KQTwlk9pT#QB_WMG}mZQbabEid) z%EvY9@B3Tyy2nxdJ!!qT)bk(%G=8Ymo-g0l&kOxds@O=z%2hZ+wO&3v5%R+bRv*3_ zW33P@7v73yrt@DPuACvudS$15J9aeR{88!S<;KG1!`=26fntBEG-eL3;iojp4dFC_ zJA-4hvq!_+s&pW?iMsjiQSY=VKcZQpuXohV2#;z2khNe~6N`MTnZAy8Iqaz<^pIQD zt)H2feOmSX6Q*%RyeM%-M31#ScZ2t&#~q`ZNO+C<#H1~b+r18q_OmugkrMEI>pb0% z$zv`|B*TVcBZe_+U`sT}`56$zN(2O*U;;sPh(M4tBoIWfYZYfnT)>-S9JQW8cNr^c zSxe?E=_BlUMTjx5(oPlP>{$aaUS7fS$M?LtCmmQ3%no<<9A5=@C3EKJIyUCp+BZ}Z zAJ&Jem>0{Errui%#F_)mUAYKzw9j8FOi4q^3pQ{fomlC7`gXALtPjZHE6Dsx1FuZt zJ^Gb;wdzA1&d!1&llv4&9o3|OsL|(9x~p^Pp^VQrK|2D`yjxwx!9aPIk#aW$7B0ZJ1?alPYShbI7dQ(ktEMZ7I;2 zo}()FYbT*hZ<(d681UT1jUCamB~5If6QB&P@&Yk>6f_T81bav%kAEunTCmoUBQ#qi zNLFvpBRS&Ih$Ay5g7U@n60rz&VCaT_v}tOPRET=(s5*Lrvs62je0dcSU4=dnwcZRj+2YBmX{XIoY`Vnfc)$6u($ zxMC8eB~{*xqs7lVnT_IE3rXMX%2@iYLX|wwnlB9Yb>4_dk=dth>2+cM;~QaXy4Tgo z>)+m%HtvXrhckRrL1$p&l%W=zrM|N>9R!dah7Eq^`0TNX!Zh7{GHykC}=FyQfK6k&PJYsWbB3IoyUU;#pI<~ks zcI~;{#(*P6CD7Z81(g1-PWQt}>`IR^=cP)0KKiO^X}3W6c9X#VWt`$8VNMdAp;}Tk zlrFh8TGPvVCbfFmhM@ZXG^sB}qXiDk8wqs+L1HdxS3XRbY^)41vIs~8N!>lA9JMSe z5CevJpsoSK;vY?gYHvgn05!%YE0O6*+|r8}f0n0#rQF%VSPk^4r*vRpV=#gl*BeW| zxsOM>oOOqM4;NUuxhK2D5b#{oKj}UPgP6R^y7{9{h7YxxhGE~UK#svu>J5w50p-a1 z;PK&d3$2t3N*>CQLba&fFN+r4dy>3TnDLW%4YN)@orAkktFpLfMM((bf{a&#`<31r zYi%d>ubK#hQRDnEu148_jPpCtdY^_@KM!$LtsySy8&!PL(DIp=)BJ*>D4yDc6WXko zMU0Bp1oEf9w(>l-=&Zx>5@5kh^Qz}}X-Hp<5+K1x81?05nQHN(KlM}Glu8qJLk*ek zIBEC{Ef{?C-VwVhm_PcENcv!?n&R~$cT`g)X7*qmZwX+QV4EP|p5^Qs#L9H4%HnaV z3VSyazsvrG`%yLHf{fjI@pNuptBv9NghM0TSXO{~xll`|yN=CumEpX%Pb!YU{w6W1 zaC;-?==GiRu^UJVImh!pq8lrLjMeJ-X;?uqm9Y8o@+P>u@E-o$4n`At*$xKe+<+5< z_O^^CK!3ed8mp>mvSzhw#4UR#iwJH#WUMxj_!&Sb*9LGWzGf03l5DrF& z{yIh{{w@{~f+{ieg|6ot33YzlHVPrVh8a^zBD{YFP_#yAjcbCIZtWx%j0E5dl zxXmdkAz;}@)1Dl5nB#)H#Py63<+TLQXCg_SGu%@v(zOQy` zypY{~(=k|WM+irmRoPBo`u$wrW5N4;aJ2A%G={qx8&p_#HhaF4J~;?=w`b;uLq~p& zA{FkmPjikUSE|lWB4&z=Gp2}No|DU>CMgV2RDu_bHy1BT|4k}X2E{%sm2bJ!A5z0c z8a|28sHZ5b)ToStPTq!x)ubp4x^iYCxgi&winA+34n?_JMNBPY#)-C976n18i~@rG zVhCm-8X=u9KM0ItDcjgarRStF`iV>UD~Mc9Qtp32oK(;pc`#C2hHWGt^9kGF789}*lrPC2)5(5 z)%s)W7z=~vs@F6_?fyae0X*FgcEj|XOuGB2gz1bIvazFS_bQp3LUIU+(<_&dn!|F7U!8t-dX0H;2x% zKgxV~K)C1FC+$phI9DKY;#Ibg!$W;4ZSNy$_M?9pkqxQC_hr+R88lD(z{}|Q;aj{? z`Pwq&nfp1-v!<%ou5q)E*?4>y4jm26SKl{xzxKp^w+;?TjYx07bw2B&Q=|sMjaMH< z*2ic2X;Y6+TiZ8sfyy2{ruQ;)Dm$BJ-{@tw~0Qh*UO(< z47%J}*)B%6n->Kh^o2t@KN5HGYmLoJO|D!nrql_xm+9VVo*ev{QbIs7f;psrt`_~7 zKK;`CL+z-N++PL!wYKdSEFc+t>hMdY+wZ`?7XADRY=HgWJmLQ+0s39i?}Z?L%Gv{$ z#Qv=;c5Nl{gCBP5oloI_Fp;AFI3&{@ZX8vKj9CH$2T`x6fUP!RwCztdyCqyNfG{EA)xS0?-${RdC+ mJN)+?@lOG9q<^g5zcWT9IT)~d{HUWu0(66!5C*y*cmD(Oa9S_` diff --git a/e2e/protractor/resources/test-files/file2-xlsx.xlsx b/e2e/protractor/resources/test-files/file2-xlsx.xlsx deleted file mode 100644 index 3039a7cdc8579121f821af3dbb78590f00ba19f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 97629 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 diff --git a/e2e/protractor/resources/test-files/file_unsupported.3DS b/e2e/protractor/resources/test-files/file_unsupported.3DS deleted file mode 100755 index be21d11425..0000000000 --- a/e2e/protractor/resources/test-files/file_unsupported.3DS +++ /dev/null @@ -1 +0,0 @@ -™™ \ No newline at end of file diff --git a/e2e/protractor/resources/test-files/protected.pdf b/e2e/protractor/resources/test-files/protected.pdf deleted file mode 100644 index d0d083f114898f160cad4b07fdb57046a46cfdf8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18052 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�n$D2q#UC*S2dlsX7xdxaRXh03)Na4ql`!)% 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 diff --git a/e2e/protractor/smartrunner-factory.js b/e2e/protractor/smartrunner-factory.js deleted file mode 100644 index 21703e8c89..0000000000 --- a/e2e/protractor/smartrunner-factory.js +++ /dev/null @@ -1,14 +0,0 @@ -const SmartRunnerFactory = require('protractor-smartrunner').SmartRunnerFactory; -const resolve = require('path').resolve; - -const outputDirectory = process.env.SMART_RUNNER_DIRECTORY; -const repoHash = process.env.GIT_HASH; - -console.log(`SmartRunner's repoHash: "${repoHash}"`); -console.log(`SmartRunner's outputDirectory: "${outputDirectory}"`); - -module.exports = new SmartRunnerFactory({ - repoHash, - ...(outputDirectory ? { outputDirectory: resolve(__dirname, '..', outputDirectory) } : {}), - exclusionPath: resolve(__dirname, 'protractor.excludes.json') -}); diff --git a/e2e/protractor/suites/actions/upload-download/upload-file.test.ts b/e2e/protractor/suites/actions/upload-download/upload-file.test.ts deleted file mode 100755 index a272a0ec55..0000000000 --- a/e2e/protractor/suites/actions/upload-download/upload-file.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * from Hyland Software. If not, see . - */ - -import { AdminActions, LoginPage, BrowsingPage, RepoClient, Utils, UserActions } from '@alfresco/aca-testing-shared'; - -describe('Upload files', () => { - const username = `user-${Utils.random()}`; - - const folder1 = `folder1-${Utils.random()}`; - let folder1Id: string; - - const apis = { - user: new RepoClient(username, username) - }; - - const loginPage = new LoginPage(); - const page = new BrowsingPage(); - const { dataTable } = page; - - const adminApiActions = new AdminActions(); - const userActions = new UserActions(); - - beforeAll(async () => { - await adminApiActions.createUser({ username }); - await userActions.login(username, username); - - folder1Id = await apis.user.createFolder(folder1); - - await loginPage.loginWith(username); - }); - - beforeEach(async () => { - await page.clickPersonalFilesAndWait(); - await dataTable.doubleClickOnRowByName(folder1); - await page.toolbar.openUploadMenu(); - await page.toolbar.menu.uploadFilesInput.sendKeys(`${__dirname}/upload-file.test.ts`); - await page.toolbar.closeUploadMenu(); - await page.uploadFilesDialog.uploadDialog.isVisible(); - }); - - afterAll(async () => { - await apis.user.nodes.deleteNodeById(folder1Id); - }); - - it('Upload a file', async () => { - const uploadedFiles = await dataTable.isItemPresent('upload-file.test.ts'); - expect(uploadedFiles).toBe(true, 'file not uploaded'); - }); - - it('[T14752064] Close the upload dialog ', async () => { - await page.uploadFilesDialog.closeUploadButton.click(); - await page.uploadFilesDialog.uploadDialog.isPresent(); - expect(await page.uploadFilesDialog.uploadDialog.isVisible()).toBe(false); - }); - - it('[T14752051] Minimize / maximize the upload dialog ', async () => { - await page.uploadFilesDialog.minimizeButton.click(); - expect(await page.uploadFilesDialog.uploadedFiles.waitNotVisible()).toBe(true); - - await page.uploadFilesDialog.maximizeButton.click(); - expect(await page.uploadFilesDialog.uploadedFiles.waitVisible()).toBe(true); - }); - - it('[T14752053] Upload history is expunged on browser login/logout ', async () => { - await page.signOut(); - await loginPage.loginWith(username); - const isUploadDialogVisible = await page.uploadFilesDialog.uploadDialog.isVisible(); - - expect(isUploadDialogVisible).toBe(false); - }); - - it('[T14752052] Upload dialog remains fixed in the browser when user performs other actions in parallel ', async () => { - expect(page.uploadFilesDialog.uploadDialog.isVisible()).toBe(true); - await page.clickPersonalFiles(); - expect(page.uploadFilesDialog.uploadDialog.isVisible()).toBe(true); - }); -}); diff --git a/e2e/protractor/tsconfig.e2e.adf.json b/e2e/protractor/tsconfig.e2e.adf.json deleted file mode 100644 index 1b1fa99bb5..0000000000 --- a/e2e/protractor/tsconfig.e2e.adf.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../../tsconfig.adf.json", - "compilerOptions": { - "outDir": "../../out-tsc/e2e", - "baseUrl": "./", - "module": "commonjs", - "target": "es2017", - "types": ["jasmine", "jasminewd2", "node"], - "skipLibCheck": true, - "paths": { - "@alfresco/aca-testing-shared": ["../../projects/aca-testing-shared/src/index.ts"] - } - }, - "exclude": ["node_modules"] -} diff --git a/e2e/protractor/tsconfig.e2e.json b/e2e/protractor/tsconfig.e2e.json deleted file mode 100755 index 14c0002b0e..0000000000 --- a/e2e/protractor/tsconfig.e2e.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "../../out-tsc/e2e", - "baseUrl": "./", - "module": "commonjs", - "target": "es2017", - "types": ["jasmine", "jasminewd2", "node", "@playwright/test"], - "skipLibCheck": true, - "paths": { - "@alfresco/aca-testing-shared": ["../../projects/aca-testing-shared/src/index.ts"], - "@alfresco/playwright-shared": ["../../projects/aca-playwright-shared/src/index.ts"] - } - }, - "exclude": ["node_modules"] -} diff --git a/package-lock.json b/package-lock.json index e7d939af69..5d43d8c302 100644 --- a/package-lock.json +++ b/package-lock.json @@ -95,10 +95,6 @@ "node-stream-zip": "^1.14.0", "nx": "17.3.1", "prettier": "2.8.8", - "protractor": "~7.0.0", - "protractor-retry-angular-cli": "^2.0.3", - "protractor-screenshoter-plugin": "0.10.3", - "protractor-smartrunner": "^2.0.0-beta6", "selenium-webdriver": "^4.1.1", "stylelint": "^15.11.0", "stylelint-config-standard-scss": "^7.0.1", @@ -10581,7 +10577,9 @@ "version": "0.0.32", "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", "integrity": "sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/@types/qs": { "version": "6.9.15", @@ -11761,15 +11759,6 @@ "node": ">=0.10.0" } }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array.prototype.findlastindex": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", @@ -11880,15 +11869,6 @@ "node": ">=0.8" } }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -12410,6 +12390,8 @@ "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "minimist": "^1.2.0" }, @@ -12528,6 +12510,8 @@ "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "https-proxy-agent": "^2.2.1" } @@ -12537,6 +12521,8 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "es6-promisify": "^5.0.0" }, @@ -12549,6 +12535,8 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -12558,6 +12546,8 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -12795,36 +12785,6 @@ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, - "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai-as-promised": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", - "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", - "dev": true, - "dependencies": { - "check-error": "^1.0.2" - }, - "peerDependencies": { - "chai": ">= 2.1.2 < 6" - } - }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -12854,18 +12814,6 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -12926,13 +12874,6 @@ "node": ">=8" } }, - "node_modules/circular-json": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", - "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==", - "deprecated": "CircularJSON is in maintenance only, flatted is its successor.", - "dev": true - }, "node_modules/cjs-module-lexer": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", @@ -14381,18 +14322,6 @@ "node": ">=8" } }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/deep-equal": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", @@ -15384,13 +15313,17 @@ "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "es6-promise": "^4.0.3" } @@ -16832,29 +16765,6 @@ "node": ">=10" } }, - "node_modules/filename-reserved-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", - "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/filenamify": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.1.0.tgz", - "integrity": "sha512-KQV/uJDI9VQgN7sHH1Zbk6+42cD6mnQ2HONzkXUfPJ+K2FC8GZ1dpewbbHw0Sz8Tf5k3EVdHVayM4DoAwWlmtg==", - "dev": true, - "dependencies": { - "filename-reserved-regex": "^2.0.0", - "strip-outer": "^1.0.1", - "trim-repeated": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -17428,15 +17338,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -19584,6 +19485,8 @@ "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", "integrity": "sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "exit": "^0.1.2", "glob": "^7.0.6", @@ -19614,6 +19517,8 @@ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "optional": true, + "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -19633,13 +19538,17 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", "integrity": "sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/jasmine/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -19652,6 +19561,8 @@ "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", "integrity": "sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">= 6.9.x" } @@ -21699,15 +21610,6 @@ "node": ">=0.10.0" } }, - "node_modules/klaw-sync": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", - "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11" - } - }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -22396,15 +22298,6 @@ "node": ">=8.0" } }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -23257,15 +23150,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -25231,15 +25115,6 @@ "node": ">=8" } }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/pdfjs-dist": { "version": "3.3.122", "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.3.122.tgz", @@ -26416,6 +26291,8 @@ "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", "dev": true, + "optional": true, + "peer": true, "dependencies": { "@types/q": "^0.0.32", "@types/selenium-webdriver": "^3.0.0", @@ -26441,201 +26318,21 @@ "node": ">=10.13.x" } }, - "node_modules/protractor-retry-angular-cli": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/protractor-retry-angular-cli/-/protractor-retry-angular-cli-2.0.3.tgz", - "integrity": "sha512-sPamB1TUMf8R5cHTopyrj1OYsDedXU4Q7viic3Z+K7jWk7+TkbUlEukd57HHbVddSh5iGHWmghsWEUqiZnhT8g==", - "dev": true, - "dependencies": { - "array-unique": "~0.3.2", - "chai": "4.x", - "chai-as-promised": "7.x", - "cross-spawn": "^7.0.2", - "debug": "^4.1.1", - "lodash": "^4.17.19", - "mkdirp": "^1.0.3", - "q": "^1.5.1", - "xml2js": "~0.4.23", - "yargs": "^16.1.1" - } - }, - "node_modules/protractor-retry-angular-cli/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/protractor-retry-angular-cli/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/protractor-retry-angular-cli/node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/protractor-retry-angular-cli/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/protractor-retry-angular-cli/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/protractor-screenshoter-plugin": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/protractor-screenshoter-plugin/-/protractor-screenshoter-plugin-0.10.3.tgz", - "integrity": "sha512-OF9kGe1rMxBQY4uXzXQUFT14EB83rz8DlDcxmH5HcOHPBpUhGh+Nwo7+K87w1LoLcTuGdG7Bz+/hGwoGguDfsA==", - "dev": true, - "dependencies": { - "circular-json": "^0.5.1", - "fs-extra": "^7.0.0", - "klaw-sync": "^6.0.0", - "lodash": "^4.17.11", - "mkdirp": "^0.5.1", - "moment": "^2.20.1", - "q": "^1.5.1", - "screenshoter-report-analyzer": "^0.6", - "uuid": "^3.1.0" - } - }, - "node_modules/protractor-screenshoter-plugin/node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/protractor-screenshoter-plugin/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/protractor-screenshoter-plugin/node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/protractor-screenshoter-plugin/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/protractor-smartrunner": { - "version": "2.0.0-beta9", - "resolved": "https://registry.npmjs.org/protractor-smartrunner/-/protractor-smartrunner-2.0.0-beta9.tgz", - "integrity": "sha512-E4X8hpipnoxTuta0uT6o1p9ZcjLzKFHH3jr/xgp3VQJ2PKHHmsGkal5JdbQJ4tURLUG2Yg9sP+7yDOCrrsbW7Q==", - "dev": true, - "dependencies": { - "filenamify": "4.1.0", - "fs-extra": "8.1.0" - }, - "peerDependencies": { - "protractor": "~7.0.0" - } - }, - "node_modules/protractor-smartrunner/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/protractor-smartrunner/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/protractor-smartrunner/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/protractor/node_modules/@types/selenium-webdriver": { "version": "3.0.26", "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz", "integrity": "sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/protractor/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -26645,6 +26342,8 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -26654,6 +26353,8 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -26670,6 +26371,8 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -26681,6 +26384,8 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -26690,6 +26395,8 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -26702,6 +26409,8 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -26713,13 +26422,17 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/protractor/node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -26730,6 +26443,8 @@ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "optional": true, + "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -26750,6 +26465,8 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -26763,6 +26480,8 @@ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "optional": true, + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -26775,6 +26494,8 @@ "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "jszip": "^3.1.3", "rimraf": "^2.5.4", @@ -26790,6 +26511,8 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -26799,6 +26522,8 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "source-map": "^0.5.6" } @@ -26808,6 +26533,8 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ansi-regex": "^2.0.0" }, @@ -26820,6 +26547,8 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.8.0" } @@ -26829,6 +26558,8 @@ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "os-tmpdir": "~1.0.1" }, @@ -26841,6 +26572,8 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -26855,6 +26588,8 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -26864,6 +26599,8 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -26879,6 +26616,8 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -26890,13 +26629,17 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/protractor/node_modules/yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", @@ -26919,6 +26662,8 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -27691,7 +27436,9 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/requireindex": { "version": "1.2.0", @@ -28191,6 +27938,8 @@ "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "https-proxy-agent": "^2.2.1" }, @@ -28203,6 +27952,8 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "es6-promisify": "^5.0.0" }, @@ -28215,6 +27966,8 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -28224,6 +27977,8 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -28257,15 +28012,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/screenshoter-report-analyzer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/screenshoter-report-analyzer/-/screenshoter-report-analyzer-0.6.0.tgz", - "integrity": "sha512-T4EbdD57N2fvptFj8GpLlD5lxfwzO3iRv3QEXkSNJWcotLySnrJDaLtzFRo64JBsQ4RomWrSt31XGgBoNOI8KA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/secure-compare": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", @@ -29501,18 +29247,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-outer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", - "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/strong-log-transformer": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", @@ -30652,18 +30386,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/trim-repeated": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", - "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ts-loader": { "version": "9.5.1", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", @@ -31574,6 +31296,8 @@ "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "@types/selenium-webdriver": "^3.0.0", "selenium-webdriver": "^3.0.1" @@ -31586,7 +31310,9 @@ "version": "3.0.26", "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz", "integrity": "sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/webdriver-js-extender/node_modules/glob": { "version": "7.2.3", @@ -31594,6 +31320,8 @@ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "optional": true, + "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -31614,6 +31342,8 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -31627,6 +31357,8 @@ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "optional": true, + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -31639,6 +31371,8 @@ "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "jszip": "^3.1.3", "rimraf": "^2.5.4", @@ -31654,6 +31388,8 @@ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "os-tmpdir": "~1.0.1" }, @@ -32194,7 +31930,9 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/which-typed-array": { "version": "1.1.15", diff --git a/package.json b/package.json index 19a5812d8b..525e69029a 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,6 @@ "build.release": "npm run build -- --configuration=production,release", "test": "nx test", "lint": "NODE_OPTIONS=--max_old_space_size=4096 nx run-many --all --target=lint", - "update-webdriver": "./scripts/webdriver-update-newest/update-to-newest-webdriver.sh", - "e2e": "npm run update-webdriver && protractor $SUITE", "inspect.bundle": "nx build content-ce --configuration production --stats-json && npx webpack-bundle-analyzer dist/content-ce/stats.json", "prepare": "husky install", "stylelint": "stylelint \"{app,projects}/**/*.scss\"", @@ -119,10 +117,6 @@ "node-stream-zip": "^1.14.0", "nx": "17.3.1", "prettier": "2.8.8", - "protractor": "~7.0.0", - "protractor-retry-angular-cli": "^2.0.3", - "protractor-screenshoter-plugin": "0.10.3", - "protractor-smartrunner": "^2.0.0-beta6", "selenium-webdriver": "^4.1.1", "stylelint": "^15.11.0", "stylelint-config-standard-scss": "^7.0.1", diff --git a/projects/aca-playwright-shared/src/api/file-actions.ts b/projects/aca-playwright-shared/src/api/file-actions.ts index 4453f5f36d..938c3b4712 100644 --- a/projects/aca-playwright-shared/src/api/file-actions.ts +++ b/projects/aca-playwright-shared/src/api/file-actions.ts @@ -26,7 +26,7 @@ import * as fs from 'fs'; import { ApiClientFactory } from './api-client-factory'; import { Utils } from '../utils'; import { NodeBodyCreate, NodeEntry, ResultSetPaging } from '@alfresco/js-api'; -import { waitForApi } from '@alfresco/aca-testing-shared'; +import { waitForApi } from '@alfresco/playwright-shared'; export class FileActionsApi { private apiService: ApiClientFactory; diff --git a/projects/aca-playwright-shared/src/page-objects/playwright-base.ts b/projects/aca-playwright-shared/src/page-objects/playwright-base.ts index c330176f2b..74d7aa6634 100644 --- a/projects/aca-playwright-shared/src/page-objects/playwright-base.ts +++ b/projects/aca-playwright-shared/src/page-objects/playwright-base.ts @@ -23,7 +23,7 @@ */ import { Page } from '@playwright/test'; -import { GenericLogger, LoggerLike } from '@alfresco/aca-testing-shared'; +import { GenericLogger, LoggerLike } from '@alfresco/playwright-shared'; export abstract class PlaywrightBase { public page: Page; diff --git a/projects/aca-testing-shared/src/utilities/api.ts b/projects/aca-playwright-shared/src/utils/api.ts similarity index 86% rename from projects/aca-testing-shared/src/utilities/api.ts rename to projects/aca-playwright-shared/src/utils/api.ts index 1be01599b5..dd8b20b34d 100644 --- a/projects/aca-testing-shared/src/utilities/api.ts +++ b/projects/aca-playwright-shared/src/utils/api.ts @@ -31,16 +31,16 @@ export async function waitForApi(apiCall: ApiCall, predicate: ApiResultPre if (predicate(apiCallResult)) { return Promise.resolve(apiCallResult); } else { - return Promise.reject(apiCallResult); + return Promise.reject(new Error(`API call did not satisfy predicate: ${JSON.stringify(apiCallResult)}`)); } }; return retryCall(apiCallWithPredicateChecking, retry, delay); } -function retryCall(fn: () => Promise, retry: number = 30, delay: number = 1000): Promise { +function retryCall(fn: () => Promise, retry: number = 30, delay: number = 1000): Promise { const pause = (duration) => new Promise((res) => setTimeout(res, duration)); - const run = (retries) => fn().catch((err) => (retries > 1 ? pause(delay).then(() => run(retries - 1)) : Promise.reject(err))); + const run = (retries) => fn().catch((err) => (retries > 1 ? pause(delay).then(() => run(retries - 1)) : Promise.reject(new Error(`API call did not satisfy predicate: ${JSON.stringify(err)}`)))); return run(retry); } diff --git a/projects/aca-playwright-shared/src/utils/index.ts b/projects/aca-playwright-shared/src/utils/index.ts index 2b1e87374d..1fcc5cdf5f 100644 --- a/projects/aca-playwright-shared/src/utils/index.ts +++ b/projects/aca-playwright-shared/src/utils/index.ts @@ -30,3 +30,5 @@ export * from './utils'; export * from './library-errors'; export * from './config'; export * from './error-strings'; +export * from './api'; +export * from './logger'; diff --git a/projects/aca-testing-shared/src/utilities/logger.ts b/projects/aca-playwright-shared/src/utils/logger.ts similarity index 86% rename from projects/aca-testing-shared/src/utilities/logger.ts rename to projects/aca-playwright-shared/src/utils/logger.ts index 9036e80e11..f0e8a38db4 100644 --- a/projects/aca-testing-shared/src/utilities/logger.ts +++ b/projects/aca-playwright-shared/src/utils/logger.ts @@ -32,12 +32,12 @@ export const errorColor = '\x1b[31m%s\x1b[0m'; export type LOG_LEVEL = 'TRACE' | 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'SILENT'; export class LogLevelsEnum extends Number { - static TRACE: number = 5; - static DEBUG: number = 4; - static INFO: number = 3; - static WARN: number = 2; - static ERROR: number = 1; - static SILENT: number = 0; + public static readonly TRACE: number = 5; + public static readonly DEBUG: number = 4; + public static readonly INFO: number = 3; + public static readonly WARN: number = 2; + public static readonly ERROR: number = 1; + public static readonly SILENT: number = 0; } export const logLevels: { level: LogLevelsEnum; name: LOG_LEVEL }[] = [ @@ -65,19 +65,19 @@ export class GenericLogger implements LoggerLike { } info(...messages: string[]): void { - if (this.level >= LogLevelsEnum.INFO) { + if (Number(this.level) >= LogLevelsEnum.INFO) { console.log(infoColor, messages.join('')); } } log(...messages: string[]): void { - if (this.level >= LogLevelsEnum.TRACE) { + if (Number(this.level) >= LogLevelsEnum.TRACE) { console.log(logColor, messages.join('')); } } warn(...messages: string[]): void { - if (this.level >= LogLevelsEnum.WARN) { + if (Number(this.level) >= LogLevelsEnum.WARN) { console.log(warnColor, messages.join('')); } } diff --git a/projects/aca-testing-shared/package.json b/projects/aca-testing-shared/package.json deleted file mode 100644 index a7a9f0289f..0000000000 --- a/projects/aca-testing-shared/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "aca-testing-shared", - "version": "3.0.0", - "license": "LGPL-3.0", - "main": "src/index.ts", - "dependencies": { - "tslib": "^2.0.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/Alfresco/alfresco-content-app.git" - } -} diff --git a/projects/aca-testing-shared/project.json b/projects/aca-testing-shared/project.json deleted file mode 100644 index b91a11a3cd..0000000000 --- a/projects/aca-testing-shared/project.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "aca-testing-shared", - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "projects/aca-testing-shared/src", - "projectType": "library", - "prefix": "lib" -} diff --git a/projects/aca-testing-shared/src/components/breadcrumb/breadcrumb.ts b/projects/aca-testing-shared/src/components/breadcrumb/breadcrumb.ts deleted file mode 100755 index 0901217083..0000000000 --- a/projects/aca-testing-shared/src/components/breadcrumb/breadcrumb.ts +++ /dev/null @@ -1,40 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { Component } from '../component'; - -export class Breadcrumb extends Component { - items = this.allByCss('.adf-breadcrumb-item'); - - constructor(ancestor?: string) { - super('adf-breadcrumb', ancestor); - } - - async getAllItems(): Promise { - return this.items.map(async (elem) => { - const str = await elem.getText(); - return str.split('\nchevron_right')[0]; - }); - } -} diff --git a/projects/aca-testing-shared/src/components/component.ts b/projects/aca-testing-shared/src/components/component.ts deleted file mode 100755 index 911a068750..0000000000 --- a/projects/aca-testing-shared/src/components/component.ts +++ /dev/null @@ -1,60 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { ElementFinder, browser, by, ElementArrayFinder, ProtractorBrowser } from 'protractor'; -import { waitForPresence } from '../utilities'; - -export abstract class Component { - component: ElementFinder; - - protected byCss(css: string, root: ElementFinder | ProtractorBrowser = this.component): ElementFinder { - return root.element(by.css(css)); - } - - protected byCssText(css: string, text: string, root: ElementFinder | ProtractorBrowser = this.component): ElementFinder { - return root.element(by.cssContainingText(css, text)); - } - - protected byId(css: string, root: ElementFinder | ProtractorBrowser = this.component): ElementFinder { - return root.element(by.id(css)); - } - - protected byTitleAttr(title: string, root: ElementFinder | ProtractorBrowser = this.component): ElementFinder { - return root.element(by.css(`[title=${title}]`)); - } - - protected allByCss(css: string, root: ElementFinder | ProtractorBrowser = this.component): ElementArrayFinder { - return root.all(by.css(css)); - } - - protected constructor(selector: string, ancestor?: string) { - const locator = selector; - - this.component = ancestor ? browser.$$(ancestor).first().$$(locator).first() : browser.$$(locator).first(); - } - - async wait() { - await waitForPresence(this.component); - } -} diff --git a/projects/aca-testing-shared/src/components/components.ts b/projects/aca-testing-shared/src/components/components.ts deleted file mode 100755 index 2ec38a4270..0000000000 --- a/projects/aca-testing-shared/src/components/components.ts +++ /dev/null @@ -1,35 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -export * from './login/login'; -export * from './header/header'; -export * from './pageLayoutHeader/pageLayoutHeader'; -export * from './data-table/data-table'; -export * from './dialog/confirm-dialog'; -export * from './dialog/create-edit-folder-dialog'; -export * from './pagination/pagination'; -export * from './sidenav/sidenav'; -export * from './toolbar/toolbar'; -export * from './breadcrumb/breadcrumb'; -export * from './viewer/viewer'; diff --git a/projects/aca-testing-shared/src/components/data-table/data-table.ts b/projects/aca-testing-shared/src/components/data-table/data-table.ts deleted file mode 100755 index 1845af612d..0000000000 --- a/projects/aca-testing-shared/src/components/data-table/data-table.ts +++ /dev/null @@ -1,251 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { browser, by, ElementArrayFinder, ElementFinder } from 'protractor'; -import { Component } from '../component'; -import { Menu } from '../menu/menu'; -import { Utils, waitForPresence, waitUntilElementIsClickable } from '../../utilities'; - -export class DataTable extends Component { - private static selectors = { - columnHeader: '.adf-datatable-row .adf-datatable-cell-header .adf-datatable-cell-value', - sortedColumnHeader: ` - .adf-datatable__header--sorted-asc .adf-datatable-cell-header-content .adf-datatable-cell-value, - .adf-datatable__header--sorted-desc .adf-datatable-cell-header-content .adf-datatable-cell-value - `, - row: '.adf-datatable-row[data-automation-id^="datatable-row"]', - cell: '.adf-datatable-cell-container', - lockOwner: '.aca-locked-by', - searchResultsRow: 'aca-search-results-row', - searchResultsRowLine: 'span' - }; - - head = this.byCss('.adf-datatable-header'); - body = this.byCss('.adf-datatable-body'); - emptyList = this.byCss('div.adf-no-content-container'); - emptyListTitle = this.byCss('.adf-empty-content__title'); - emptyListSubtitle = this.byCss('.adf-empty-content__subtitle'); - emptySearchText = this.byCss('.empty-search__text'); - selectedRow = this.byCss('.adf-datatable-row.adf-is-selected'); - - menu = new Menu(); - - constructor(ancestor?: string) { - super('adf-datatable', ancestor); - } - - async waitForHeader(): Promise { - return waitForPresence(this.head, '--- timeout waitForHeader ---'); - } - - async waitForBody(): Promise { - return waitForPresence(this.body, '--- timeout waitForBody ---'); - } - - private getColumnHeaders(): ElementArrayFinder { - const locator = by.css(DataTable.selectors.columnHeader); - return this.head.all(locator); - } - - async getColumnHeadersText(): Promise { - return this.getColumnHeaders().getText(); - } - - private getRows(): ElementArrayFinder { - return this.body.all(by.css(DataTable.selectors.row)); - } - - async getRowsCount(): Promise { - return this.getRows().count(); - } - - private getSelectedRows(): ElementArrayFinder { - return this.body.all(by.css('.adf-datatable-row.adf-is-selected')); - } - - async getSelectedRowsCount(): Promise { - return this.getSelectedRows().count(); - } - - getRowByName(name: string, location: string = ''): ElementFinder { - if (location) { - return this.body - .all(by.cssContainingText(DataTable.selectors.row, name)) - .filter(async (elem) => browser.isElementPresent(elem.element(by.cssContainingText(DataTable.selectors.cell, location)))) - .first(); - } - return this.body.element(by.cssContainingText(DataTable.selectors.row, name)); - } - - getRowCells(name: string, location: string = ''): ElementArrayFinder { - return this.getRowByName(name, location).all(by.css(DataTable.selectors.cell)); - } - - private getRowFirstCell(name: string, location: string = ''): ElementFinder { - return this.getRowCells(name, location).get(0); - } - - async hasCheckMarkIcon(itemName: string, location: string = ''): Promise { - const row = this.getRowByName(itemName, location); - return row.element(by.css('.mat-icon[class*="selected"]')).isPresent(); - } - - async hasLockIcon(itemName: string, location: string = ''): Promise { - const row = this.getRowByName(itemName, location); - return row.element(by.css('img[src*="lock"]')).isPresent(); - } - - private async hasLockOwnerInfo(itemName: string, location: string = ''): Promise { - const row = this.getRowByName(itemName, location); - return row.element(by.css(DataTable.selectors.lockOwner)).isPresent(); - } - - async getLockOwner(itemName: string, location: string = ''): Promise { - if (await this.hasLockOwnerInfo(itemName, location)) { - const row = this.getRowByName(itemName, location); - return row.$(DataTable.selectors.lockOwner).$('.aca-locked-by--name').getText(); - } - return ''; - } - - async doubleClickOnRowByName(name: string, location: string = ''): Promise { - try { - const item = this.getRowFirstCell(name, location); - await waitUntilElementIsClickable(item); - await browser.actions().mouseMove(item).perform(); - await browser.actions().doubleClick().perform(); - } catch (error) { - console.error(`--- doubleClickOnRowByName catch : failed to double click on ${name} from location : ${location} : `, error); - } - } - - async selectItem(name: string, location: string = ''): Promise { - const isSelected = await this.hasCheckMarkIcon(name, location); - if (!isSelected) { - try { - const item = this.getRowFirstCell(name, location); - await item.click(); - } catch (e) { - console.error(`--- select item catch : failed to select ${name} from location : ${location} : `, e); - } - } - } - - async unselectItem(name: string, location: string = ''): Promise { - const isSelected = await this.hasCheckMarkIcon(name, location); - if (isSelected) { - try { - const item = this.getRowFirstCell(name, location); - await item.click(); - } catch (e) { - console.error(`--- unselect item catch : failed to unselect ${name} from location : ${location} : `, e); - } - } - } - - async selectMultipleItems(names: string[], location: string = ''): Promise { - await this.clearSelection(); - await Utils.pressCmd(); - for (const name of names) { - await this.selectItem(name, location); - } - await Utils.releaseKeyPressed(); - } - - async clearSelection(): Promise { - try { - const count = await this.getSelectedRowsCount(); - if (count > 0) { - await browser.refresh(); - await this.wait(); - } - } catch (error) { - console.error('------ clearSelection catch : ', error); - } - } - - private getItemLocationEl(name: string): ElementFinder { - return this.getRowByName(name).element(by.css('.aca-location-link')); - } - - async clickItemLocation(name: string): Promise { - await this.getItemLocationEl(name).click(); - } - - async isEmpty(): Promise { - return this.emptyList.isPresent(); - } - - async getEmptyStateTitle(): Promise { - const isEmpty = await this.isEmpty(); - if (isEmpty) { - return this.emptyListTitle.getText(); - } - return ''; - } - - async getEmptyStateSubtitle(): Promise { - const isEmpty = await this.isEmpty(); - if (isEmpty) { - return this.emptyListSubtitle.getText(); - } - return ''; - } - - async isItemPresent(name: string, location?: string): Promise { - return this.getRowByName(name, location).isPresent(); - } - - private async getEntireDataTableText(): Promise { - return this.getRows().map((row) => { - return row.all(by.css(DataTable.selectors.cell)).map(async (cell) => { - return cell.getText(); - }); - }); - } - - async getSitesNameAndVisibility(): Promise { - const data: string[] = await this.getEntireDataTableText(); - return data.reduce((acc: any, cell) => { - acc[cell[1]] = cell[4].toUpperCase(); - return acc; - }, {}); - } - - async getSitesNameAndRole(): Promise { - const data: string[] = await this.getEntireDataTableText(); - return data.reduce((acc: any, cell) => { - acc[cell[1]] = cell[3]; - return acc; - }, {}); - } - - private getSearchResultsRows(): ElementArrayFinder { - return this.body.all(by.css(DataTable.selectors.searchResultsRow)); - } - - getNthSearchResultsRow(nth: number): ElementFinder { - return this.getSearchResultsRows().get(nth - 1); - } -} diff --git a/projects/aca-testing-shared/src/components/dialog/confirm-dialog.ts b/projects/aca-testing-shared/src/components/dialog/confirm-dialog.ts deleted file mode 100755 index c5acf65234..0000000000 --- a/projects/aca-testing-shared/src/components/dialog/confirm-dialog.ts +++ /dev/null @@ -1,49 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { by } from 'protractor'; -import { GenericDialog } from './generic-dialog'; -import { isPresentAndEnabled } from '../../utilities'; - -export class ConfirmDialog extends GenericDialog { - cancelButton = this.childElement(by.buttonText('Cancel')); - keepButton = this.childElement(by.buttonText('Keep')); - deleteButton = this.childElement(by.buttonText('Delete')); - - constructor() { - super('adf-confirm-dialog'); - } - - async getText(): Promise { - return this.content.getText(); - } - - async isKeepEnabled(): Promise { - return isPresentAndEnabled(this.keepButton); - } - - async isDeleteEnabled(): Promise { - return isPresentAndEnabled(this.deleteButton); - } -} diff --git a/projects/aca-testing-shared/src/components/dialog/content-node-selector-dialog.ts b/projects/aca-testing-shared/src/components/dialog/content-node-selector-dialog.ts deleted file mode 100755 index ffdeb4a248..0000000000 --- a/projects/aca-testing-shared/src/components/dialog/content-node-selector-dialog.ts +++ /dev/null @@ -1,70 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { by, browser } from 'protractor'; -import { GenericDialog } from './generic-dialog'; -import { waitForStaleness, waitForPresence, click } from '../../utilities'; -import { DataTable } from '../data-table/data-table'; - -export class ContentNodeSelectorDialog extends GenericDialog { - copyButton = this.childElement(by.cssContainingText('[data-automation-id="content-node-selector-actions-choose"]', 'Copy')); - - locationDropDown = this.rootElem.element(by.id('site-dropdown-container')); - locationPersonalFiles = browser.element(by.cssContainingText('.mat-mdc-option .mdc-list-item__primary-text', 'Personal Files')); - locationFileLibraries = browser.element(by.cssContainingText('.mat-mdc-option .mdc-list-item__primary-text', 'My Libraries')); - - searchInput = this.rootElem.element(by.css('#searchInput')); - - dataTable = new DataTable('.adf-content-node-selector-dialog'); - - constructor() { - super('.adf-content-node-selector-dialog'); - } - - get content() { - return this.rootElem.element(by.css('.adf-content-node-selector-content')); - } - - async waitForDropDownToClose(): Promise { - await waitForStaleness(browser.$('.mat-mdc-option .mdc-list-item__primary-text')); - } - - async selectLocation(location: string): Promise { - await click(this.locationDropDown); - - if (location === 'Personal Files') { - await click(this.locationPersonalFiles); - } else { - await click(this.locationFileLibraries); - } - - await this.waitForDropDownToClose(); - } - - async selectDestination(folderName: string): Promise { - const row = this.dataTable.getRowByName(folderName); - await click(row); - await waitForPresence(browser.element(by.css('.adf-is-selected'))); - } -} diff --git a/projects/aca-testing-shared/src/components/dialog/create-edit-folder-dialog.ts b/projects/aca-testing-shared/src/components/dialog/create-edit-folder-dialog.ts deleted file mode 100755 index 34ac02a662..0000000000 --- a/projects/aca-testing-shared/src/components/dialog/create-edit-folder-dialog.ts +++ /dev/null @@ -1,83 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { by } from 'protractor'; -import { GenericDialog } from './generic-dialog'; -import { click, getInputValue, isPresentAndDisplayed, isPresentAndEnabled, typeText, waitUntilElementIsClickable } from '../../utilities'; - -export class CreateOrEditFolderDialog extends GenericDialog { - createButton = this.childElement(by.cssContainingText('.mat-mdc-dialog-actions button', 'Create')); - cancelButton = this.childElement(by.id('adf-folder-cancel-button')); - updateButton = this.childElement(by.cssContainingText('.mat-mdc-dialog-actions button', 'Update')); - - nameInput = this.rootElem.element(by.id('adf-folder-name-input')); - descriptionTextArea = this.rootElem.element(by.id('adf-folder-description-input')); - validationMessage = this.rootElem.element(by.css('.mat-mdc-form-field-hint span')); - - constructor() { - super('adf-folder-dialog'); - } - - async waitForDialogToOpen() { - await super.waitForDialogToOpen(); - await waitUntilElementIsClickable(this.nameInput); - } - - async isUpdateButtonEnabled(): Promise { - return isPresentAndEnabled(this.updateButton); - } - - async isCancelButtonEnabled(): Promise { - return isPresentAndEnabled(this.cancelButton); - } - - async getValidationMessage(): Promise { - if (await isPresentAndDisplayed(this.validationMessage)) { - return this.validationMessage.getText(); - } else { - return ''; - } - } - - async getName(): Promise { - return getInputValue(this.nameInput); - } - - async getDescription(): Promise { - return getInputValue(this.descriptionTextArea); - } - - async enterName(name: string): Promise { - await typeText(this.nameInput, name); - } - - async enterDescription(description: string): Promise { - await typeText(this.descriptionTextArea, description); - } - - async clickCancel(): Promise { - await click(this.cancelButton); - await this.waitForDialogToClose(); - } -} diff --git a/projects/aca-testing-shared/src/components/dialog/generic-dialog.ts b/projects/aca-testing-shared/src/components/dialog/generic-dialog.ts deleted file mode 100644 index 4a746d9f09..0000000000 --- a/projects/aca-testing-shared/src/components/dialog/generic-dialog.ts +++ /dev/null @@ -1,70 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { ElementFinder, by, browser, Locator } from 'protractor'; -import { isPresentAndDisplayed, waitForPresence, waitForStaleness, waitUntilElementIsVisible } from '../../utilities'; - -export abstract class GenericDialog { - protected constructor(private rootCssSelector?: string) {} - - get rootElem(): ElementFinder { - return browser.element(by.css(this.rootCssSelector)); - } - - get title(): ElementFinder { - return this.rootElem.element(by.css('.mat-mdc-dialog-title')); - } - - get content(): ElementFinder { - return this.rootElem.element(by.css('.mat-mdc-dialog-content')); - } - - async getText(): Promise { - return this.content.getText(); - } - - async waitForDialogToOpen(): Promise { - await waitForPresence(this.rootElem); - await waitUntilElementIsVisible(this.content); - await waitForPresence(browser.element(by.css('.cdk-overlay-backdrop'))); - } - - async waitForDialogToClose(): Promise { - try { - await waitForStaleness(this.content); - } catch {} - } - - async isDialogOpen(): Promise { - return isPresentAndDisplayed(this.rootElem); - } - - async getDialogTitle(): Promise { - return this.title.getText(); - } - - protected childElement(selector: Locator): ElementFinder { - return this.rootElem.element(selector); - } -} diff --git a/projects/aca-testing-shared/src/components/dialog/index.ts b/projects/aca-testing-shared/src/components/dialog/index.ts deleted file mode 100644 index 759fb64553..0000000000 --- a/projects/aca-testing-shared/src/components/dialog/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -export * from './confirm-dialog'; -export * from './content-node-selector-dialog'; -export * from './create-edit-folder-dialog'; -export * from './generic-dialog'; -export * from './manage-versions-dialog'; -export * from './share-dialog'; -export * from './upload-new-version-dialog'; -export * from './upload-files-dialog'; diff --git a/projects/aca-testing-shared/src/components/dialog/manage-versions-dialog.ts b/projects/aca-testing-shared/src/components/dialog/manage-versions-dialog.ts deleted file mode 100755 index fdae40e7df..0000000000 --- a/projects/aca-testing-shared/src/components/dialog/manage-versions-dialog.ts +++ /dev/null @@ -1,46 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { by } from 'protractor'; -import { GenericDialog } from './generic-dialog'; -import { Menu } from '../menu/menu'; -import { click } from '../../utilities'; - -export class ManageVersionsDialog extends GenericDialog { - menu = new Menu(); - - constructor() { - super('.adf-new-version-uploader-dialog'); - } - - async clickActionButton(version: string): Promise { - await click(this.childElement(by.id(`adf-version-list-action-menu-button-${version}`))); - await this.menu.waitForMenuToOpen(); - } - - async viewFileVersion(version: string): Promise { - await this.clickActionButton(version); - await this.menu.clickMenuItem('View'); - } -} diff --git a/projects/aca-testing-shared/src/components/dialog/share-dialog.ts b/projects/aca-testing-shared/src/components/dialog/share-dialog.ts deleted file mode 100755 index f1b4317456..0000000000 --- a/projects/aca-testing-shared/src/components/dialog/share-dialog.ts +++ /dev/null @@ -1,41 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { by } from 'protractor'; -import { GenericDialog } from './generic-dialog'; - -export class ShareDialog extends GenericDialog { - labels = this.rootElem.all(by.css('.adf-share-link__label')); - url = this.childElement(by.css(`[data-automation-id='adf-share-link']`)); - closeButton = this.childElement(by.css(`[data-automation-id='adf-share-dialog-close']`)); - - constructor() { - super('.adf-share-dialog'); - } - - async clickClose(): Promise { - await this.closeButton.click(); - await this.waitForDialogToClose(); - } -} diff --git a/projects/aca-testing-shared/src/components/dialog/upload-files-dialog.ts b/projects/aca-testing-shared/src/components/dialog/upload-files-dialog.ts deleted file mode 100644 index 98f9094bd1..0000000000 --- a/projects/aca-testing-shared/src/components/dialog/upload-files-dialog.ts +++ /dev/null @@ -1,39 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { TestElement } from '../../utilities'; - -export class UploadFilesDialog { - uploadDialog = TestElement.byCss('.adf-upload-dialog'); - closeUploadButton = TestElement.byCss('.adf-upload-dialog [id="adf-upload-dialog-close"]'); - minimizeButton = TestElement.byCss('.adf-upload-dialog mat-icon[title="Minimize"]'); - maximizeButton = TestElement.byCss('.adf-upload-dialog mat-icon[title="Maximize"]'); - uploadedFiles = TestElement.byCss('.adf-file-uploading-row__name'); - - async closeUploadDialog(): Promise { - if (await this.uploadDialog.isVisible()) { - await this.closeUploadButton.click(); - } - } -} diff --git a/projects/aca-testing-shared/src/components/dialog/upload-new-version-dialog.ts b/projects/aca-testing-shared/src/components/dialog/upload-new-version-dialog.ts deleted file mode 100755 index a2e6eaee6f..0000000000 --- a/projects/aca-testing-shared/src/components/dialog/upload-new-version-dialog.ts +++ /dev/null @@ -1,56 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { by } from 'protractor'; -import { GenericDialog } from './generic-dialog'; -import { isPresentAndEnabled, typeText } from '../../utilities'; - -export class UploadNewVersionDialog extends GenericDialog { - cancelButton = this.childElement(by.cssContainingText('.mat-button-wrapper', 'Cancel')); - uploadButton = this.childElement(by.cssContainingText('.mat-button-wrapper', 'Upload')); - majorOption = this.childElement(by.cssContainingText(`.mat-radio-label`, 'major')); - minorOption = this.childElement(by.cssContainingText(`.mat-radio-label`, 'minor')); - description = this.childElement(by.css('textarea')); - - constructor() { - super('.adf-new-version-uploader-dialog'); - } - - async isCancelButtonEnabled(): Promise { - return isPresentAndEnabled(this.cancelButton); - } - - async isUploadButtonEnabled(): Promise { - return isPresentAndEnabled(this.uploadButton); - } - - async clickCancel(): Promise { - await this.cancelButton.click(); - await this.waitForDialogToClose(); - } - - async enterDescription(description: string): Promise { - await typeText(this.description, description); - } -} diff --git a/projects/aca-testing-shared/src/components/header/header.ts b/projects/aca-testing-shared/src/components/header/header.ts deleted file mode 100755 index 9a38e71ff6..0000000000 --- a/projects/aca-testing-shared/src/components/header/header.ts +++ /dev/null @@ -1,60 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { by, browser } from 'protractor'; -import { Component } from '../component'; -import { Menu } from '../menu/menu'; -import { Toolbar } from '../toolbar/toolbar'; -import { SearchInput } from '../search'; -import { click, waitElement } from '../../utilities'; - -export class Header extends Component { - userMenuButton = this.byCss(`.aca-user-menu-button`); - sidenavToggle = this.byCss(`.aca-sidenav-header-title-logo`); - - menu = new Menu(); - toolbar = new Toolbar(); - searchInput = new SearchInput(); - - constructor(ancestor?: string) { - super('app-sidenav-header', ancestor); - } - - async openMoreMenu(): Promise { - await click(this.userMenuButton); - await this.menu.waitForMenuToOpen(); - } - - async isSidenavExpanded(): Promise { - return browser.isElementPresent(by.css(`[data-automation-id='expanded']`)); - } - - async expandSideNav(): Promise { - const expanded = await this.isSidenavExpanded(); - if (!expanded) { - await click(this.sidenavToggle); - await waitElement(`[data-automation-id='expanded']`); - } - } -} diff --git a/projects/aca-testing-shared/src/components/index.ts b/projects/aca-testing-shared/src/components/index.ts deleted file mode 100644 index 71090ff83c..0000000000 --- a/projects/aca-testing-shared/src/components/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -export * from './breadcrumb/breadcrumb'; -export * from './data-table/data-table'; -export * from './dialog'; -export * from './header/header'; -export * from './info-drawer'; -export * from './login/login'; -export * from './menu/menu'; -export * from './pagination/pagination'; -export * from './search'; -export * from './sidenav/sidenav'; -export * from './toolbar/toolbar'; -export * from './viewer/viewer'; -export * from './component'; -export * from './components'; diff --git a/projects/aca-testing-shared/src/components/info-drawer/index.ts b/projects/aca-testing-shared/src/components/info-drawer/index.ts deleted file mode 100644 index 7f22d9ef65..0000000000 --- a/projects/aca-testing-shared/src/components/info-drawer/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -export * from './info-drawer-comments-tab'; -export * from './info-drawer-metadata-library'; -export * from './info-drawer'; diff --git a/projects/aca-testing-shared/src/components/info-drawer/info-drawer-comments-tab.ts b/projects/aca-testing-shared/src/components/info-drawer/info-drawer-comments-tab.ts deleted file mode 100755 index 5c807c3b67..0000000000 --- a/projects/aca-testing-shared/src/components/info-drawer/info-drawer-comments-tab.ts +++ /dev/null @@ -1,115 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { by, browser, until } from 'protractor'; -import { Component } from '../component'; -import { BROWSER_WAIT_TIMEOUT } from '../../configs'; -import { click, typeText, waitUntilElementIsVisible } from '../../utilities'; - -export class CommentsTab extends Component { - commentsContainer = this.byCss('.adf-comments-container'); - commentsHeader = this.byCss('.adf-comments-header'); - commentTextarea = this.byCss('.adf-comments-input-container textarea'); - addCommentButton = this.byCss('button.adf-comments-input-add'); - commentListItem = by.css('.adf-comment-list-item'); - commentUserAvatar = by.css('.adf-comment-img-container'); - commentUser = by.css('.adf-comment-user-name'); - commentText = by.css('.adf-comment-message'); - commentTime = by.css('.adf-comment-message-time'); - - constructor(ancestor?: string) { - super('adf-comments', ancestor); - } - - async waitForCommentsContainer() { - await waitUntilElementIsVisible(this.commentsContainer); - } - - async getCommentsTabHeaderText(): Promise { - return this.commentsHeader.getText(); - } - - async isCommentTextAreaDisplayed(): Promise { - return browser.isElementPresent(this.commentTextarea); - } - - async isAddCommentButtonEnabled(): Promise { - const present = await browser.isElementPresent(this.addCommentButton); - if (present) { - return this.addCommentButton.isEnabled(); - } - return false; - } - - private async getCommentListItem() { - return browser.wait(until.elementLocated(this.commentListItem), BROWSER_WAIT_TIMEOUT / 2); - } - - async getCommentById(commentId?: string) { - if (commentId) { - return browser.wait(until.elementLocated(by.id(`adf-comment-${commentId}`)), BROWSER_WAIT_TIMEOUT / 2); - } - return this.getCommentListItem(); - } - - async isCommentDisplayed(commentId?: string) { - return browser.isElementPresent(await this.getCommentById(commentId)); - } - - async isCommentUserAvatarDisplayed(commentId?: string) { - const commentElement = await this.getCommentById(commentId); - return browser.isElementPresent(commentElement.findElement(this.commentUserAvatar)); - } - - async getCommentText(commentId?: string) { - const commentElement = await this.getCommentById(commentId); - const message = await commentElement.findElement(this.commentText); - return message.getText(); - } - - async getCommentUserName(commentId?: string): Promise { - const commentElement = await this.getCommentById(commentId); - const user = await commentElement.findElement(this.commentUser); - return user.getText(); - } - - async getCommentTime(commentId?: string): Promise { - const commentElement = await this.getCommentById(commentId); - const time = await commentElement.findElement(this.commentTime); - return time.getText(); - } - - async getNthCommentText(index: number): Promise { - const list = this.allByCss('mat-list-item .adf-comment-message'); - return list.get(index - 1).getText(); - } - - async typeComment(text: string): Promise { - await typeText(this.commentTextarea, text); - } - - async clickAddButton(): Promise { - await click(this.addCommentButton); - } -} diff --git a/projects/aca-testing-shared/src/components/info-drawer/info-drawer-metadata-library.ts b/projects/aca-testing-shared/src/components/info-drawer/info-drawer-metadata-library.ts deleted file mode 100755 index 9c6277f2fc..0000000000 --- a/projects/aca-testing-shared/src/components/info-drawer/info-drawer-metadata-library.ts +++ /dev/null @@ -1,217 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { by, browser } from 'protractor'; -import { Component } from '../component'; -import { waitForPresence, waitForStaleness, typeText, click } from '../../utilities'; - -export class LibraryMetadata extends Component { - visibilityDropDown = this.component.element(by.css('.mat-mdc-select')); - visibilityPublic = this.byCssText('.mat-mdc-option .mdc-list-item__primary-text', 'Public', browser); - visibilityPrivate = this.byCssText('.mat-mdc-option .mdc-list-item__primary-text', 'Private', browser); - visibilityModerated = this.byCssText('.mat-mdc-option .mdc-list-item__primary-text', 'Moderated', browser); - visibilityValue = this.byCss('[data-automation-id="library-visibility-properties-wrapper"] .mat-mdc-select'); - - hint = this.byCss('.mat-mdc-form-field-hint'); - error = this.byCss('.mat-mdc-form-field-error'); - - constructor(ancestor?: string) { - super('app-library-metadata-form', ancestor); - } - - private getLabelWrapper(label: string) { - return this.byCssText('.mat-mdc-floating-label', label); - } - - private getFieldByName(fieldName: string) { - const wrapper = this.getLabelWrapper(fieldName); - return wrapper.element(by.xpath('..')).element(by.css('.mat-mdc-input-element')); - } - - private async isFieldDisplayed(fieldName: string) { - return browser.isElementPresent(this.getFieldByName(fieldName)); - } - - private async isInputEnabled(fieldName: string) { - return this.getFieldByName(fieldName).isEnabled(); - } - - private async getValueOfField(fieldName: string) { - return this.getFieldByName(fieldName).getAttribute('value'); - } - - private async enterTextInInput(fieldName: string, text: string) { - const input = this.getFieldByName(fieldName); - await typeText(input, text); - } - - private getButton(button: string) { - return this.byCssText('.mat-mdc-card-actions .mat-mdc-button', button); - } - - private async isButtonDisplayed(button: string) { - return browser.isElementPresent(this.getButton(button)); - } - - private async isButtonEnabled(button: string) { - return this.getButton(button).isEnabled(); - } - - private async clickButton(button: string) { - await click(this.getButton(button)); - } - - async waitForVisibilityDropDownToClose() { - await waitForStaleness(browser.$('.mat-mdc-option .mdc-list-item__primary-text')); - } - - async isMessageDisplayed() { - return browser.isElementPresent(this.hint); - } - - async getMessage() { - return this.hint.getText(); - } - - async isErrorDisplayed() { - return browser.isElementPresent(this.error); - } - - async getError() { - return this.error.getText(); - } - - async isNameDisplayed() { - return this.isFieldDisplayed('Name'); - } - - async isNameEnabled() { - return this.isInputEnabled('Name'); - } - - async getName(): Promise { - return this.getValueOfField('Name'); - } - - async enterName(name: string): Promise { - await this.enterTextInInput('Name', name); - } - - async isDescriptionDisplayed() { - return this.isFieldDisplayed('Description'); - } - - async isDescriptionEnabled() { - return this.isInputEnabled('Description'); - } - - async getDescription(): Promise { - return this.getValueOfField('Description'); - } - - async enterDescription(desc: string) { - await this.enterTextInInput('Description', desc); - } - - async isVisibilityEnabled() { - const wrapper = this.getLabelWrapper('Visibility'); - const field = wrapper.element(by.xpath('..')).element(by.css('.mat-mdc-select')); - return field.isEnabled(); - } - - async isVisibilityDisplayed() { - return browser.isElementPresent(this.visibilityValue); - } - - async getVisibility(): Promise { - return this.visibilityValue.getText(); - } - - async setVisibility(visibility: string) { - const val = visibility.toLowerCase(); - - await click(this.visibilityDropDown); - await waitForPresence(this.visibilityDropDown); - - if (val === 'public') { - await click(this.visibilityPublic); - } else if (val === 'private') { - await click(this.visibilityPrivate); - } else if (val === 'moderated') { - await click(this.visibilityModerated); - } else { - console.error('----- invalid visibility', val); - } - - await this.waitForVisibilityDropDownToClose(); - } - - async isLibraryIdDisplayed() { - return this.isFieldDisplayed('Library ID'); - } - - async isLibraryIdEnabled() { - return this.isInputEnabled('Library ID'); - } - - async getLibraryId() { - return this.getValueOfField('Library ID'); - } - - async isEditLibraryPropertiesEnabled() { - return this.isButtonEnabled('Edit'); - } - - async isEditLibraryPropertiesDisplayed() { - return this.isButtonDisplayed('Edit'); - } - - async clickEditLibraryProperties() { - await this.clickButton('Edit'); - } - - async isUpdateEnabled() { - return this.isButtonEnabled('Update'); - } - - async isUpdateDisplayed() { - return this.isButtonDisplayed('Update'); - } - - async clickUpdate() { - await this.clickButton('Update'); - } - - async isCancelEnabled() { - return this.isButtonEnabled('Cancel'); - } - - async isCancelDisplayed() { - return this.isButtonDisplayed('Cancel'); - } - - async clickCancel() { - await this.clickButton('Cancel'); - } -} diff --git a/projects/aca-testing-shared/src/components/info-drawer/info-drawer.ts b/projects/aca-testing-shared/src/components/info-drawer/info-drawer.ts deleted file mode 100755 index ae6e2229b3..0000000000 --- a/projects/aca-testing-shared/src/components/info-drawer/info-drawer.ts +++ /dev/null @@ -1,97 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { browser } from 'protractor'; -import { Component } from '../component'; -import { CommentsTab } from './info-drawer-comments-tab'; -import { LibraryMetadata } from './info-drawer-metadata-library'; -import { click, TestElement, waitForPresence, waitUntilElementIsVisible } from '../../utilities'; -import { Toolbar } from '../toolbar/toolbar'; - -export class InfoDrawer extends Component { - commentsTab = new CommentsTab('adf-info-drawer'); - aboutTab = new LibraryMetadata('adf-info-drawer'); - header = this.byCss('.adf-info-drawer-layout-header'); - headerTitle = this.byCss('.adf-info-drawer-layout-header-title > div'); - tabActiveLabel = this.byCss('.mat-tab-label-active'); - expandDetailsButton = TestElement.byCss(`button[title='Expand panel']`); - selectedTab = TestElement.byCss(`.mat-tab-list [aria-selected='true'] div`); - expandedDetailsPermissionsTab = TestElement.byText('.aca-details-container .mat-tab-label-content', 'Permissions'); - previewButton = TestElement.byCss(`button[title='Preview File']`); - toolbar = new Toolbar('adf-info-drawer'); - - constructor(ancestor?: string) { - super('adf-info-drawer', ancestor); - } - - async waitForInfoDrawerToOpen() { - await waitForPresence(this.header); - } - - async isOpen() { - return browser.isElementPresent(this.header); - } - - getTabByTitle(title: string) { - return this.byCssText('.mat-tab-label-content', title); - } - - async getTabsCount(): Promise { - return this.allByCss('.mat-tab-label-content').count(); - } - - async isTabDisplayed(title: string): Promise { - if (await browser.isElementPresent(this.getTabByTitle(title))) { - return this.getTabByTitle(title).isDisplayed(); - } - - return false; - } - - async getActiveTabTitle(): Promise { - return this.tabActiveLabel.getText(); - } - - async getHeaderTitle(): Promise { - return this.headerTitle.getText(); - } - - async isPropertiesTabDisplayed() { - return this.isTabDisplayed('Properties'); - } - - async isCommentsTabDisplayed() { - return this.isTabDisplayed('Comments'); - } - - async clickCommentsTab() { - try { - await click(this.getTabByTitle('Comments')); - await this.commentsTab.waitForCommentsContainer(); - await waitUntilElementIsVisible(this.commentsTab.component); - } catch (error) { - console.error('--- info-drawer clickCommentsTab catch error: ', error); - } - } -} diff --git a/projects/aca-testing-shared/src/components/login/login.ts b/projects/aca-testing-shared/src/components/login/login.ts deleted file mode 100755 index 46399a4933..0000000000 --- a/projects/aca-testing-shared/src/components/login/login.ts +++ /dev/null @@ -1,50 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { Component } from '../component'; -import { typeText } from '../../utilities'; - -export class LoginComponent extends Component { - usernameInput = this.byCss('input#username'); - passwordInput = this.byCss('input#password'); - submitButton = this.byCss('button#login-button'); - copyright = this.byCss('.adf-copyright'); - - constructor(ancestor?: string) { - super('adf-login', ancestor); - } - - async enterUsername(username: string): Promise { - await typeText(this.usernameInput, username); - } - - async enterPassword(password: string): Promise { - await typeText(this.passwordInput, password); - } - - async enterCredentials(username: string, password: string): Promise { - await this.enterUsername(username); - await this.enterPassword(password); - } -} diff --git a/projects/aca-testing-shared/src/components/menu/menu.ts b/projects/aca-testing-shared/src/components/menu/menu.ts deleted file mode 100755 index 2c8e6b73a2..0000000000 --- a/projects/aca-testing-shared/src/components/menu/menu.ts +++ /dev/null @@ -1,66 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { ElementFinder, by, browser } from 'protractor'; -import { Component } from '../component'; -import { click, waitForPresence, waitForStaleness, waitUntilElementIsVisible } from '../../utilities'; - -export class Menu extends Component { - items = this.allByCss('.mat-mdc-menu-item'); - uploadFilesInput = this.byId('app-upload-files', browser); - cancelEditingAction = this.byCss(`.mat-mdc-menu-item[title='Cancel Editing']`); - copyAction = this.byTitleAttr('Copy'); - editFolderAction = this.byCss(`.mat-mdc-menu-item[id$='editFolder']`); - editOfflineAction = this.byCss(`.mat-mdc-menu-item[title='Edit Offline']`); - - constructor(ancestor?: string) { - super('.mat-mdc-menu-panel', ancestor); - } - - async waitForMenuToOpen(): Promise { - await waitForPresence(browser.element(by.css('.cdk-overlay-container .mat-mdc-menu-panel'))); - await waitUntilElementIsVisible(this.items.get(0)); - } - - async waitForMenuToClose(): Promise { - await waitForStaleness(browser.element(by.css('.cdk-overlay-container .mat-mdc-menu-panel'))); - } - - private getItemByLabel(menuItem: string): ElementFinder { - return this.byCssText('.mat-mdc-menu-item', menuItem); - } - - async getItemIconText(menuItem: string): Promise { - return this.getItemByLabel(menuItem).element(by.css('.mat-icon')).getText(); - } - - async clickMenuItem(menuItem: string): Promise { - try { - const elem = this.getItemByLabel(menuItem); - await click(elem); - } catch (e) { - console.error(`___click menu item catch : failed to click on ${menuItem}___`, e); - } - } -} diff --git a/projects/aca-testing-shared/src/components/pageLayoutHeader/pageLayoutHeader.ts b/projects/aca-testing-shared/src/components/pageLayoutHeader/pageLayoutHeader.ts deleted file mode 100644 index 0505595684..0000000000 --- a/projects/aca-testing-shared/src/components/pageLayoutHeader/pageLayoutHeader.ts +++ /dev/null @@ -1,39 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2020 Alfresco Software Limited - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { Component } from '../component'; -import { Menu } from '../menu/menu'; -import { Toolbar } from '../toolbar/toolbar'; -import { SearchInput } from '../search/search-input'; - -export class PageLayoutHeader extends Component { - menu = new Menu(); - toolbar = new Toolbar(); - searchInput = new SearchInput(); - - constructor(ancestor?: string) { - super('aca-page-layout', ancestor); - } -} diff --git a/projects/aca-testing-shared/src/components/pagination/pagination.ts b/projects/aca-testing-shared/src/components/pagination/pagination.ts deleted file mode 100755 index a7aaa78763..0000000000 --- a/projects/aca-testing-shared/src/components/pagination/pagination.ts +++ /dev/null @@ -1,69 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { Menu } from '../menu/menu'; -import { Component } from '../component'; - -export class Pagination extends Component { - range = this.byCss('.adf-pagination__range'); - maxItems = this.byCss('.adf-pagination__max-items'); - currentPage = this.byCss('.adf-pagination__current-page'); - totalPages = this.byCss('.adf-pagination__total-pages'); - previousButton = this.byCss('.adf-pagination__previous-button'); - nextButton = this.byCss('.adf-pagination__next-button'); - - menu: Menu = new Menu(); - - constructor(ancestor?: string) { - super('adf-pagination', ancestor); - } - - async isRangePresent() { - return this.range.isPresent(); - } - - async isMaxItemsPresent() { - return this.maxItems.isPresent(); - } - - async isCurrentPagePresent() { - return this.currentPage.isPresent(); - } - - async isTotalPagesPresent() { - return this.totalPages.isPresent(); - } - - async isPreviousButtonPresent() { - return this.previousButton.isPresent(); - } - - async isNextButtonPresent() { - return this.nextButton.isPresent(); - } - - async getRange() { - return this.range.getText(); - } -} diff --git a/projects/aca-testing-shared/src/components/search/filters/autocomplete-chips-filter.ts b/projects/aca-testing-shared/src/components/search/filters/autocomplete-chips-filter.ts deleted file mode 100644 index e1f9ed3efb..0000000000 --- a/projects/aca-testing-shared/src/components/search/filters/autocomplete-chips-filter.ts +++ /dev/null @@ -1,58 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { browser, by, ElementArrayFinder, ElementFinder, protractor } from 'protractor'; -import { GenericFilter } from './generic-filter'; - -export class AutocompleteChipsFilter extends GenericFilter { - private readonly locators = { - selectedOption: '.mat-mdc-chip span', - input: '.mat-mdc-menu-content input', - }; - - constructor(filterName: string) { - super(filterName); - } - - selectedOptions: ElementArrayFinder = this.filterDialogOpened.all(by.css(this.locators.selectedOption)); - - get filterInput(): ElementFinder { - return this.filterDialogOpened.element(by.css(this.locators.input)); - } - - async getFiltersSelectedValues(): Promise { - return this.selectedOptions.map((option) => { - return option.getText(); - }); - } - - async isFilterAutocompleteInputDisplayed(): Promise { - return this.filterInput.isDisplayed(); - } - - async setAutocompleteInputValue(value: string): Promise { - await this.filterInput.sendKeys(value); - await browser.actions().sendKeys(protractor.Key.ENTER).perform(); - } -} diff --git a/projects/aca-testing-shared/src/components/search/filters/created-date-filter.ts b/projects/aca-testing-shared/src/components/search/filters/created-date-filter.ts deleted file mode 100755 index e69de29bb2..0000000000 diff --git a/projects/aca-testing-shared/src/components/search/filters/facet-filter.ts b/projects/aca-testing-shared/src/components/search/filters/facet-filter.ts deleted file mode 100755 index 3ae703ca54..0000000000 --- a/projects/aca-testing-shared/src/components/search/filters/facet-filter.ts +++ /dev/null @@ -1,74 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { ElementFinder, ElementArrayFinder, by, browser } from 'protractor'; -import { GenericFilter } from './generic-filter'; - -export class FacetFilter extends GenericFilter { - private readonly locators = { - checkbox: '.mat-mdc-menu-content .mat-mdc-checkbox', - checkboxChecked: '.mat-mdc-menu-content .mat-mdc-checkbox.mat-mdc-checkbox-checked', - categoryInput: '.mat-mdc-menu-content input[data-automation-id^="facet-result-filter"]', - facetsFilter: '.mat-mdc-menu-content .adf-facet-result-filter' - }; - - get facets(): ElementArrayFinder { - return this.filterDialogOpened.all(by.css(this.locators.checkbox)); - } - get selectedFacets(): ElementArrayFinder { - return this.filterDialogOpened.all(by.css(this.locators.checkboxChecked)); - } - get facetsFilter(): ElementFinder { - return this.filterDialogOpened.element(by.css(this.locators.facetsFilter)); - } - get filterCategoryInput(): ElementFinder { - return this.facetsFilter.element(by.css(this.locators.categoryInput)); - } - - async getFiltersValues(): Promise { - return this.facets.map((option) => { - return option.getText(); - }); - } - - async getFiltersCheckedValues(): Promise { - return this.selectedFacets.map((option) => { - return option.getText(); - }); - } - async isFilterCategoryInputDisplayed(): Promise { - return this.filterCategoryInput.isDisplayed(); - } - - async checkCategory(name: string): Promise { - const option = this.facets.filter(async (elem) => (await elem.getText()).includes(name)).first(); - await browser.executeScript(`arguments[0].scrollIntoView();`, option); - await browser.actions().mouseMove(option).perform(); - await browser.actions().click().perform(); - } - - async filterCategoriesBy(name: string): Promise { - await this.filterCategoryInput.sendKeys(name); - } -} diff --git a/projects/aca-testing-shared/src/components/search/filters/facet-tabbed-filter.ts b/projects/aca-testing-shared/src/components/search/filters/facet-tabbed-filter.ts deleted file mode 100644 index 0e17fb1d79..0000000000 --- a/projects/aca-testing-shared/src/components/search/filters/facet-tabbed-filter.ts +++ /dev/null @@ -1,91 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { ElementFinder, ElementArrayFinder, by, browser, protractor, element } from 'protractor'; -import { GenericFilter } from './generic-filter'; -import { waitUntilElementHasText } from '../../../utilities'; - -export class FacetTabbedFilter extends GenericFilter { - private readonly locators = { - tabs: '.mat-tab-list .mat-tab-label', - chipList: '.mat-tab-body-active .adf-chip-list', - chipListInput: '.mat-tab-body-active .adf-chip-list input', - currentTabLabel: '.mat-tab-label-active .mat-tab-label-content', - chip: '.mat-mdc-chip span', - option: '.mdc-list-item__primary-text' - }; - - chips: ElementArrayFinder = this.filterDialogOpened.all(by.css(this.locators.chip)); - - get tabs(): ElementArrayFinder { - return this.filterDialogOpened.all(by.css(this.locators.tabs)); - } - - get chipList(): ElementFinder { - return this.filterDialogOpened.element(by.css(this.locators.chipList)); - } - - get chipListInput(): ElementFinder { - return this.filterDialogOpened.element(by.css(this.locators.chipListInput)); - } - - get options(): ElementArrayFinder { - return element.all(by.css(this.locators.option)); - } - - async getCurrentTabLabel(): Promise { - const label = this.filterDialogOpened.element(by.css(this.locators.currentTabLabel)); - return await label.getText(); - } - - async changeTabToModifier(): Promise { - await this.tabs.get(1).click(); - await waitUntilElementHasText(await this.filterDialogOpened.element(by.css(this.locators.currentTabLabel)), 'Modifier'); - } - - async changeTabToCreator(): Promise { - await this.tabs.get(0).click(); - await waitUntilElementHasText(await this.filterDialogOpened.element(by.css(this.locators.currentTabLabel)), 'Creator'); - } - - async isChipListDisplayed(): Promise { - return this.chipList.isDisplayed(); - } - - async getSelectedValues(): Promise { - return this.chips.map((option) => { - return option.getText(); - }); - } - - async selectChip(name: string): Promise { - await this.chipListInput.sendKeys(name); - await browser.actions().sendKeys(protractor.Key.ENTER).perform(); - } - - async getAutocompleteOptions(filterValue: string): Promise { - await this.chipListInput.sendKeys(filterValue); - return this.options.map((option) => option.getText()); - } -} diff --git a/projects/aca-testing-shared/src/components/search/filters/generic-filter.ts b/projects/aca-testing-shared/src/components/search/filters/generic-filter.ts deleted file mode 100755 index 74282709ef..0000000000 --- a/projects/aca-testing-shared/src/components/search/filters/generic-filter.ts +++ /dev/null @@ -1,92 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { ElementFinder, by, browser, element } from 'protractor'; -import { isPresentAndDisplayed, Utils, waitUntilElementIsVisible, waitUntilElementIsNotVisible, TestElement } from '../../../utilities'; - -async function waitUntilActionMenuIsVisible(): Promise { - const actionMenu = element.all(by.css('div[role="menu"]')).first(); - await waitUntilElementIsVisible(actionMenu); -} - -async function waitUntilActionMenuIsNotVisible(): Promise { - const actionMenu = element.all(by.css('div[role="menu"]')).first(); - await waitUntilElementIsNotVisible(actionMenu); -} - -export class GenericFilter { - private readonly filterName: string; - - constructor(filterName: string) { - this.filterName = filterName; - } - - private readonly selectors = { - root: 'adf-search-filter-chips', - - chip: '.mat-mdc-chip', - chipDialog: '.mat-mdc-menu-content .adf-search-filter-menu-card' - }; - - get chip(): ElementFinder { - return browser.element(by.cssContainingText(this.selectors.chip, this.filterName)); - } - get filterDialogOpened(): ElementFinder { - return browser.element(by.cssContainingText(this.selectors.chipDialog, this.filterName)); - } - - async getChipTitle(): Promise { - return browser.element(by.cssContainingText(`${this.selectors.root} ${this.selectors.chip}`, this.filterName)).getAttribute('title'); - } - - async clickApplyButton(): Promise { - await TestElement.byId('apply-filter-button').click(); - } - - async clickResetButton(): Promise { - await TestElement.byId('cancel-filter-button').click(); - } - - async isDisplayed(): Promise { - return isPresentAndDisplayed(this.chip); - } - - async isDialogPresent(): Promise { - return isPresentAndDisplayed(this.filterDialogOpened); - } - - async openDialog(): Promise { - if (!(await this.isDialogPresent())) { - await this.chip.click(); - await waitUntilActionMenuIsVisible(); - } - } - - async closeDialog(): Promise { - if (await this.isDialogPresent()) { - await Utils.pressEscape(); - await waitUntilActionMenuIsNotVisible(); - } - } -} diff --git a/projects/aca-testing-shared/src/components/search/filters/properties-filter.ts b/projects/aca-testing-shared/src/components/search/filters/properties-filter.ts deleted file mode 100644 index ddd975e010..0000000000 --- a/projects/aca-testing-shared/src/components/search/filters/properties-filter.ts +++ /dev/null @@ -1,103 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { GenericFilter } from './generic-filter'; -import { by, element, ElementArrayFinder, ElementFinder } from 'protractor'; - -export enum SizeOperator { - AT_LEAST = 'At Least', - AT_MOST = 'At Most', - EXACTLY = 'Exactly' -} - -export class PropertiesFilter extends GenericFilter { - private readonly locators = { - fileSizeOperatorSelect: '[data-automation-id=adf-search-properties-file-size-operator-select]', - fileSizeOperatorOption: '.mdc-list-item__primary-text', - selectedFileSizeOperatorOption: '.mat-mdc-select-min-line', - fileSizeInput: '[data-automation-id=adf-search-properties-file-size-input]', - fileTypeInput: '[data-automation-id=adf-search-chip-autocomplete-input]', - fileTypeOption: '.mdc-list-item__primary-text', - selectedFileTypeOption: 'adf-search-chip-autocomplete-input .mat-mdc-chip span' - }; - - constructor() { - super('Properties'); - } - - get fileTypeInput(): ElementFinder { - return this.filterDialogOpened.element(by.css(this.locators.fileTypeInput)); - } - - get fileTypeOptions(): ElementArrayFinder { - return element.all(by.css(this.locators.fileTypeOption)); - } - - get fileSizeInput(): ElementFinder { - return this.filterDialogOpened.element(by.css(this.locators.fileSizeInput)); - } - - get fileSizeOperatorSelect(): ElementFinder { - return this.filterDialogOpened.element(by.css(this.locators.fileSizeOperatorSelect)); - } - - get fileTypeOperatorOptions(): ElementArrayFinder { - return element.all(by.css(this.locators.fileSizeOperatorOption)); - } - - get selectedFileTypeOperatorOption(): ElementFinder { - return this.filterDialogOpened.element(by.css(this.locators.selectedFileSizeOperatorOption)); - } - - async getFileTypesValues(filterValue: string): Promise { - await this.fileTypeInput.sendKeys(filterValue); - return this.fileTypeOptions.map((option) => option.getText()); - } - - async selectFileType(option: string): Promise { - await this.fileTypeInput.sendKeys(option); - return this.fileTypeOptions.filter(async (element) => (await element.getText()) === option).click(); - } - - async getSelectedFileTypeOptions(): Promise { - return this.filterDialogOpened.all(by.css(this.locators.selectedFileTypeOption)).map((option) => option.getText()); - } - - async typeFileSize(fileSize: string): Promise { - await this.fileSizeInput.sendKeys(fileSize); - } - - async selectFileSizeOperator(option: string): Promise { - await this.fileSizeOperatorSelect.click(); - await this.fileTypeOperatorOptions.filter(async (element) => (await element.getText() === option)).click(); - } - - async getFileSizeOperatorValue(): Promise { - return this.selectedFileTypeOperatorOption.getText(); - } - - async getFileSizeValue(): Promise { - return this.fileSizeInput.getAttribute('value'); - } -} diff --git a/projects/aca-testing-shared/src/components/search/index.ts b/projects/aca-testing-shared/src/components/search/index.ts deleted file mode 100644 index 455f918370..0000000000 --- a/projects/aca-testing-shared/src/components/search/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -export * from './filters/autocomplete-chips-filter'; -export * from './filters/facet-filter'; -export * from './filters/generic-filter'; -export * from './filters/properties-filter'; -export * from './search-filters'; -export * from './search-input'; -export * from './search-sorting-picker'; diff --git a/projects/aca-testing-shared/src/components/search/search-filters.ts b/projects/aca-testing-shared/src/components/search/search-filters.ts deleted file mode 100755 index bad14d7dfc..0000000000 --- a/projects/aca-testing-shared/src/components/search/search-filters.ts +++ /dev/null @@ -1,43 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { by, browser } from 'protractor'; -import { Component } from '../component'; -import { FacetFilter } from './filters/facet-filter'; -import { AutocompleteChipsFilter } from './filters/autocomplete-chips-filter'; -import { PropertiesFilter } from './filters/properties-filter'; -import { FacetTabbedFilter } from './filters/facet-tabbed-filter'; - -export class SearchFilters extends Component { - resetAllButton = browser.element(by.css('button[adf-reset-search]')); - - fileType = new PropertiesFilter(); - people = new FacetTabbedFilter('People'); - location = new AutocompleteChipsFilter('Location'); - modifiedDate = new FacetFilter('Modified date'); - - constructor(ancestor?: string) { - super('adf-search-filter', ancestor); - } -} diff --git a/projects/aca-testing-shared/src/components/search/search-input.ts b/projects/aca-testing-shared/src/components/search/search-input.ts deleted file mode 100755 index 1e3cd28813..0000000000 --- a/projects/aca-testing-shared/src/components/search/search-input.ts +++ /dev/null @@ -1,172 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { browser, by } from 'protractor'; -import { Component } from '../component'; -import { click, waitElement, waitForPresence, waitUntilElementIsClickable, getUrl, TestElement } from '../../utilities'; - -export class SearchInput extends Component { - get searchButton() { - return browser.element(by.css('aca-search-input .app-search-button')); - } - - searchContainer = browser.element(by.css('.app-search-container')); - searchControl = browser.element(by.css('.app-search-control')); - - searchInput = TestElement.byCss('input[id="app-control-input"]'); - searchResult = TestElement.byCss('.search-file-name'); - - searchOptionsArea = browser.element(by.id('search-options')); - searchFilesOption = this.searchOptionsArea.element(by.cssContainingText('.mat-mdc-checkbox', 'Files')); - searchFoldersOption = this.searchOptionsArea.element(by.cssContainingText('.mat-mdc-checkbox', 'Folders')); - searchLibrariesOption = this.searchOptionsArea.element(by.cssContainingText('.mat-mdc-checkbox', 'Libraries')); - constructor(ancestor?: string) { - super('aca-search-input', ancestor); - } - - async waitForSearchControl() { - await waitForPresence(this.searchControl); - } - - async isSearchContainerDisplayed() { - const isContainerDisplayed = await this.searchContainer.isDisplayed(); - const isSearchButtonDisplayed = await this.searchButton.isDisplayed(); - - return isContainerDisplayed && isSearchButtonDisplayed; - } - - async clickSearchButton() { - await click(this.searchButton); - - await this.waitForSearchControl(); - } - - async isOptionsAreaDisplayed() { - await waitElement('.app-search-control'); - return browser.isElementPresent(this.searchOptionsArea); - } - - async clickFilesOption() { - await click(this.searchFilesOption); - } - - async clickFoldersOption() { - await click(this.searchFoldersOption); - } - - async clickLibrariesOption() { - await click(this.searchLibrariesOption); - } - - async isFilesOptionEnabled() { - const optClass = await this.searchFilesOption.getAttribute('class'); - return !optClass.includes('.mat-mdc-checkbox-disabled'); - } - - async isFoldersOptionEnabled() { - const optClass = await this.searchFoldersOption.getAttribute('class'); - return !optClass.includes('.mat-mdc-checkbox-disabled'); - } - - async isLibrariesOptionEnabled() { - const optClass = await this.searchLibrariesOption.getAttribute('class'); - return !optClass.includes('.mat-mdc-checkbox-disabled'); - } - - async isFilesOptionChecked() { - const optClass = await this.searchFilesOption.getAttribute('class'); - return optClass.includes('.mat-mdc-checkbox-checked'); - } - - async isFoldersOptionChecked() { - const optClass = await this.searchFoldersOption.getAttribute('class'); - return optClass.includes('.mat-mdc-checkbox-checked'); - } - - async isLibrariesOptionChecked() { - const optClass = await this.searchLibrariesOption.getAttribute('class'); - return optClass.includes('.mat-mdc-checkbox-checked'); - } - - async clearOptions() { - if (await this.isFilesOptionChecked()) { - await this.clickFilesOption(); - } - if (await this.isFoldersOptionChecked()) { - await this.clickFoldersOption(); - } - if (await this.isLibrariesOptionChecked()) { - await this.clickLibrariesOption(); - } - } - async checkOnlyFiles() { - await this.clearOptions(); - await this.clickFilesOption(); - } - - async checkOnlyFolders() { - await this.clearOptions(); - await this.clickFoldersOption(); - } - - async checkFilesAndFolders() { - await this.clearOptions(); - await this.clickFilesOption(); - await this.clickFoldersOption(); - } - - async checkLibraries() { - await this.clearOptions(); - await this.clickLibrariesOption(); - } - - async searchForLibrary(text: string) { - await waitUntilElementIsClickable(this.searchInput.elementFinder); - await this.searchInput.typeText(text); - } - - async searchFor(text: string) { - await waitUntilElementIsClickable(this.searchInput.elementFinder); - await this.searchInput.typeText(text); - await click(this.searchButton); - } - - async searchByURL(text: string) { - const query = Buffer.from(text, 'utf-8').toString(); - await getUrl(`#/search;q=${query}`); - } - - async searchUntilResult(text: string, methodType: 'URL' | 'UI', waitPerSearch: number = 2000, timeout: number = 20000) { - const attempts = Math.round(timeout / waitPerSearch); - let loopCount = 0; - return new Promise((resolve, reject) => { - const check = async () => { - loopCount++; - loopCount >= attempts ? reject('File not found') : methodType === 'UI' ? await this.searchFor(text) : await this.searchByURL(text); - (await this.searchResult.isPresent(waitPerSearch)) ? resolve('File found') : setTimeout(check, waitPerSearch); - }; - return check(); - }); - } -} diff --git a/projects/aca-testing-shared/src/components/search/search-sorting-picker.ts b/projects/aca-testing-shared/src/components/search/search-sorting-picker.ts deleted file mode 100755 index 5dce0ff840..0000000000 --- a/projects/aca-testing-shared/src/components/search/search-sorting-picker.ts +++ /dev/null @@ -1,73 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { by, browser } from 'protractor'; -import { Component } from '../component'; -import { isPresentAndDisplayed, waitUntilElementIsVisible, click } from '../../utilities'; - -export type SortByType = 'Relevance' | 'Title' | 'Filename' | 'Modified date' | 'Modifier' | 'Created date' | 'Size' | 'Type'; -export class SearchSortingPicker extends Component { - actionMenu = browser.element(by.css('aca-search-action-menu > button')); - sortOrderButton = browser.element(by.css('#aca-button-sorting-menu')); - sortByDropdownExpanded = browser.element.all(by.css('.mat-mdc-menu-panel')).get(1); - sortByList = this.sortByDropdownExpanded.all(by.css('button')); - - constructor(ancestor?: string) { - super('aca-button-action-menu', ancestor); - } - - async waitForSortByDropdownToExpand(): Promise { - await waitUntilElementIsVisible(this.sortByDropdownExpanded); - } - - async isSortOrderButtonDisplayed(): Promise { - return isPresentAndDisplayed(this.actionMenu); - } - async isSortByDropdownExpanded(): Promise { - return isPresentAndDisplayed(this.sortByDropdownExpanded); - } - - async clickSortByDropdown(): Promise { - await click(this.actionMenu); - await click(this.sortOrderButton); - await this.waitForSortByDropdownToExpand(); - } - - async getSortByOptionsList(): Promise { - return this.sortByList.map(async (option) => { - return option.getText(); - }); - } - - async sortBy(option: SortByType, direction: string): Promise { - if (!(await this.isSortByDropdownExpanded())) { - await this.clickSortByDropdown(); - } - const elem = browser.element(by.cssContainingText('.mat-mdc-menu-item', option)); - const optionId = await elem.getAttribute('id'); - await click(elem); - const directionSortElement = browser.element(by.id(`${optionId}-${direction.toLocaleLowerCase()}`)); - await click(directionSortElement); - } -} diff --git a/projects/aca-testing-shared/src/components/sidenav/sidenav.ts b/projects/aca-testing-shared/src/components/sidenav/sidenav.ts deleted file mode 100755 index 1767c050cc..0000000000 --- a/projects/aca-testing-shared/src/components/sidenav/sidenav.ts +++ /dev/null @@ -1,83 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { ElementFinder, by, browser } from 'protractor'; -import { Menu } from '../menu/menu'; -import { Component } from '../component'; -import { click } from '../../utilities'; - -export class Sidenav extends Component { - links = this.component.all(by.css('.item')); - personalFiles = this.byCss(`[data-automation-id='app.navbar.personalFiles']`); - fileLibraries = this.byCss(`[data-automation-id='app.navbar.libraries.menu']`); - myLibraries = this.byCss(`[data-automation-id='app.navbar.libraries.files']`, browser); - favoriteLibraries = this.byCss(`[data-automation-id='app.navbar.libraries.favorite']`, browser); - shared = this.byCss(`[data-automation-id='app.navbar.shared']`); - recentFiles = this.byCss(`[data-automation-id='app.navbar.recentFiles']`); - favorites = this.byCss(`[data-automation-id='app.navbar.favorites']`); - trash = this.byCss(`[data-automation-id='app.navbar.trashcan']`); - - menu: Menu = new Menu(); - - constructor(ancestor?: string) { - super('app-sidenav', ancestor); - } - - async isActive(name: string): Promise { - const cssClass = await this.getLinkLabel(name).getAttribute('class'); - return cssClass.includes('action-button--active'); - } - - private getLinkLabel(name: string): ElementFinder { - switch (name) { - case 'Personal Files': - return this.personalFiles; - case 'File Libraries': - return this.fileLibraries; - case 'My Libraries': - return this.myLibraries; - case 'Favorite Libraries': - return this.favoriteLibraries; - case 'Shared': - return this.shared; - case 'Recent Files': - return this.recentFiles; - case 'Favorites': - return this.favorites; - case 'Trash': - return this.trash; - default: - return this.personalFiles; - } - } - - async clickLink(name: string): Promise { - try { - const link = this.getLinkLabel(name); - await click(link); - } catch (error) { - console.error(`---- clickLink catch : sidebar navigation failed to click on - ${name} : `, error); - } - } -} diff --git a/projects/aca-testing-shared/src/components/toolbar/toolbar.ts b/projects/aca-testing-shared/src/components/toolbar/toolbar.ts deleted file mode 100755 index eeb059d336..0000000000 --- a/projects/aca-testing-shared/src/components/toolbar/toolbar.ts +++ /dev/null @@ -1,118 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { by, browser, By, element } from 'protractor'; -import { Menu } from '../menu/menu'; -import { Component } from '../component'; -import { click, Utils } from '../../utilities'; - -export class Toolbar extends Component { - menu = new Menu(); - - buttons = this.allByCss('button'); - createButton = element(By.css('[id="app.toolbar.create"]')); - uploadButton = element(By.css('[id="app.toolbar.upload"]')); - downloadButton = element(By.css(`.mat-icon-button[title='Download']`)); - viewDetailsButton = element(By.css(`button[title='View Details']`)); - permanentlyDeleteButton = element(By.css(`button[title='Permanently Delete']`)); - restoreButton = element(By.css(`button[title='Restore']`)); - searchIconButton = element(By.css(`button[title='Search']`)); - viewerDownloadButton = element(By.css('[id="app.viewer.download"]')); - - constructor(ancestor?: string) { - super('aca-toolbar', ancestor); - } - - async isButtonPresent(title: string) { - const element = this.byCss(`button[title="${title}"]`); - return element.isPresent(); - } - - async clickSearchIconButton() { - await click(this.searchIconButton); - } - - async openMoreMenu(): Promise { - const btnMoreActions = element(By.css('button[id="app.toolbar.more"]')); - await btnMoreActions.isPresent(); - await click(btnMoreActions); - - await this.menu.waitForMenuToOpen(); - await browser.sleep(500); - } - - async closeMoreMenu() { - await Utils.pressEscape(); - } - - async openUploadMenu(): Promise { - await click(this.uploadButton); - await this.menu.waitForMenuToOpen(); - } - - async closeUploadMenu(): Promise { - await click(element(by.css('button[id="app.toolbar.upload"]'))); - await this.menu.waitForMenuToClose(); - } - - async clickMoreActionsFavorite(): Promise { - await this.openMoreMenu(); - await this.menu.clickMenuItem('Favorite'); - } - - async clickMoreActionsRemoveFavorite(): Promise { - await this.openMoreMenu(); - await this.menu.clickMenuItem('Remove Favorite'); - } - - async clickMoreActionsDelete(): Promise { - await this.openMoreMenu(); - await this.menu.clickMenuItem('Delete'); - } - - async clickMoreActionsManageVersions(): Promise { - await this.openMoreMenu(); - await this.menu.clickMenuItem('Manage Versions'); - } - - async clickMoreActionsCopy(): Promise { - await this.openMoreMenu(); - await this.menu.copyAction.click(); - } - - async clickMoreActionsEditOffline(): Promise { - await this.openMoreMenu(); - await this.menu.clickMenuItem('Edit Offline'); - } - - async clickMoreActionsCancelEditing(): Promise { - await this.openMoreMenu(); - await this.menu.clickMenuItem('Cancel Editing'); - } - - async clickMoreActionsUploadNewVersion(): Promise { - await this.openMoreMenu(); - await this.menu.clickMenuItem('Upload New Version'); - } -} diff --git a/projects/aca-testing-shared/src/components/viewer/viewer.ts b/projects/aca-testing-shared/src/components/viewer/viewer.ts deleted file mode 100755 index 74e7be8d40..0000000000 --- a/projects/aca-testing-shared/src/components/viewer/viewer.ts +++ /dev/null @@ -1,68 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { browser } from 'protractor'; -import { Component } from '../component'; -import { Toolbar } from '../toolbar/toolbar'; -import { waitForPresence } from '../../utilities'; - -export class Viewer extends Component { - root = browser.$('adf-viewer'); - viewerLayout = this.byCss('.adf-viewer-render-layout-content'); - viewerContainer = this.byCss('.adf-viewer-render-content-container'); - closeButton = this.byCss('.adf-viewer-close-button'); - fileTitle = this.byCss('.adf-viewer__file-title'); - - toolbar = new Toolbar('adf-viewer'); - - constructor(ancestor?: string) { - super('adf-viewer', ancestor); - } - - async waitForViewerToOpen(): Promise { - try { - await waitForPresence(this.viewerContainer); - await waitForPresence(this.viewerLayout); - } catch (error) { - console.error('\n-----> catch waitForViewerToOpen <-----\n', error); - } - } - - async waitForFileTitleToBeDisplayed(fileTitle: string): Promise { - try { - const fileName = this.byCssText('.adf-viewer__display-name', `${fileTitle}`); - await waitForPresence(fileName); - } catch (error) { - console.error('\n-----> catch waitForFileTitle <-----\n', error); - } - } - - async isViewerOpened() { - return browser.isElementPresent(this.viewerLayout); - } - - async getFileTitle(): Promise { - return this.fileTitle.getText(); - } -} diff --git a/projects/aca-testing-shared/src/configs.ts b/projects/aca-testing-shared/src/configs.ts deleted file mode 100755 index 752eded795..0000000000 --- a/projects/aca-testing-shared/src/configs.ts +++ /dev/null @@ -1,96 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -export const BROWSER_WAIT_TIMEOUT = 10000; - -// Application configs -export const USE_HASH_STRATEGY = true; - -// Application Routes -export const APP_ROUTES = { - FAVORITES: '/favorites', - MY_LIBRARIES: '/libraries', - FAVORITE_LIBRARIES: '/favorite/libraries', - LOGIN: '/login', - LOGOUT: '/logout', - PERSONAL_FILES: '/personal-files', - RECENT_FILES: '/recent-files', - SHARED_FILES: '/shared', - TRASHCAN: '/trashcan' -}; - -// Sidebar labels -export const SIDEBAR_LABELS = { - PERSONAL_FILES: 'Personal Files', - MY_LIBRARIES: 'My Libraries', - FAVORITE_LIBRARIES: 'Favorite Libraries', - SHARED_FILES: 'Shared', - RECENT_FILES: 'Recent Files', - FAVORITES: 'Favorites', - TRASH: 'Trash' -}; - -// Site visibility -export const SITE_VISIBILITY = { - PUBLIC: 'PUBLIC', - MODERATED: 'MODERATED', - PRIVATE: 'PRIVATE' -}; - -// Site roles -export const SITE_ROLES = { - SITE_CONSUMER: { - ROLE: 'SiteConsumer', - LABEL: 'Consumer' - }, - SITE_COLLABORATOR: { - ROLE: 'SiteCollaborator', - LABEL: 'Collaborator' - }, - SITE_CONTRIBUTOR: { - ROLE: 'SiteContributor', - LABEL: 'Contributor' - }, - SITE_MANAGER: { - ROLE: 'SiteManager', - LABEL: 'Manager' - }, - NONE: { - LABEL: 'Not a member' - } -}; - -export const FILES = { - docxFile: 'file-docx.docx', - docxFile2: 'file2-docx.docx', - xlsxFile: 'file-xlsx.xlsx', - xlsxFile2: 'file2-xlsx.xlsx', - pdfFile: 'file-pdf.pdf', - unsupportedFile: 'file_unsupported.3DS', - protectedFile: { - name: 'protected.pdf', - password: '0000' - }, - jpgFile: 'file-jpg.jpg' -}; diff --git a/projects/aca-testing-shared/src/index.ts b/projects/aca-testing-shared/src/index.ts deleted file mode 100644 index ec6dab9269..0000000000 --- a/projects/aca-testing-shared/src/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -export * from './components'; -export * from './pages'; -export * from './utilities'; -export * from './configs'; diff --git a/projects/aca-testing-shared/src/pages/browsing-page.ts b/projects/aca-testing-shared/src/pages/browsing-page.ts deleted file mode 100755 index de8b905559..0000000000 --- a/projects/aca-testing-shared/src/pages/browsing-page.ts +++ /dev/null @@ -1,95 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { Header, DataTable, Pagination, Toolbar, Breadcrumb, Sidenav, PageLayoutHeader } from '../components'; -import { SIDEBAR_LABELS } from '../configs'; -import { Page } from './page'; - -export class BrowsingPage extends Page { - header = new Header(this.appRoot); - sidenav = new Sidenav(this.appRoot); - toolbar = new Toolbar('.aca-page-layout'); - breadcrumb = new Breadcrumb(this.appRoot); - pageLayoutHeader = new PageLayoutHeader(this.appRoot); - dataTable = new DataTable(this.appRoot); - pagination = new Pagination(this.appRoot); - - async clickPersonalFiles(): Promise { - await this.sidenav.clickLink(SIDEBAR_LABELS.PERSONAL_FILES); - } - - async clickPersonalFilesAndWait(): Promise { - await this.clickPersonalFiles(); - await this.dataTable.waitForHeader(); - } - - async goToFavoriteLibraries(): Promise { - await this.sidenav.clickLink(SIDEBAR_LABELS.FAVORITE_LIBRARIES); - } - - async goToMyLibraries(): Promise { - await this.sidenav.clickLink(SIDEBAR_LABELS.MY_LIBRARIES); - } - - async goToMyLibrariesAndWait(): Promise { - await this.goToMyLibraries(); - await this.dataTable.waitForHeader(); - } - - async clickRecentFiles(): Promise { - await this.sidenav.clickLink(SIDEBAR_LABELS.RECENT_FILES); - } - - async clickRecentFilesAndWait(): Promise { - await this.clickRecentFiles(); - await this.dataTable.waitForHeader(); - } - - async clickSharedFiles(): Promise { - await this.sidenav.clickLink(SIDEBAR_LABELS.SHARED_FILES); - } - - async clickSharedFilesAndWait(): Promise { - await this.clickSharedFiles(); - await this.dataTable.waitForHeader(); - } - - async clickFavorites(): Promise { - await this.sidenav.clickLink(SIDEBAR_LABELS.FAVORITES); - } - - async clickFavoritesAndWait(): Promise { - await this.clickFavorites(); - await this.dataTable.waitForHeader(); - } - - async clickTrash(): Promise { - await this.sidenav.clickLink(SIDEBAR_LABELS.TRASH); - } - - async clickTrashAndWait(): Promise { - await this.clickTrash(); - await this.dataTable.waitForHeader(); - } -} diff --git a/projects/aca-testing-shared/src/pages/index.ts b/projects/aca-testing-shared/src/pages/index.ts deleted file mode 100755 index dac437105c..0000000000 --- a/projects/aca-testing-shared/src/pages/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -export * from './browsing-page'; -export * from './login-page'; -export * from './search-results-page'; diff --git a/projects/aca-testing-shared/src/pages/login-page.ts b/projects/aca-testing-shared/src/pages/login-page.ts deleted file mode 100755 index 3fba6f06b4..0000000000 --- a/projects/aca-testing-shared/src/pages/login-page.ts +++ /dev/null @@ -1,65 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { browser } from 'protractor'; -import { LoginComponent } from '../components'; -import { Page } from './page'; -import { APP_ROUTES } from '../configs'; -import { click, waitForPresence } from '../utilities'; - -export class LoginPage extends Page { - login = new LoginComponent(this.appRoot); - - constructor() { - super(APP_ROUTES.LOGIN); - } - - async load() { - await super.load(); - - if (await this.isLoggedIn()) { - await this.signOut(); - } - - await waitForPresence(this.login.submitButton); - } - - async loginWith(username: string, password?: string) { - try { - const pass = password || username; - - await this.load(); - - await this.login.enterCredentials(username, pass); - await click(this.login.submitButton); - await this.waitForApp(); - } catch (error) { - console.error(`----- loginWith catch : failed to login with user: ${username} : ${error}`); - } - } - - async loginWithAdmin() { - await this.loginWith(browser.params.ADMIN_USERNAME, browser.params.ADMIN_PASSWORD); - } -} diff --git a/projects/aca-testing-shared/src/pages/page.ts b/projects/aca-testing-shared/src/pages/page.ts deleted file mode 100755 index 275bbc13c5..0000000000 --- a/projects/aca-testing-shared/src/pages/page.ts +++ /dev/null @@ -1,113 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { browser, by, ElementFinder, WebElement } from 'protractor'; -import { APP_ROUTES, USE_HASH_STRATEGY } from '../configs'; -import { Utils, waitElement, waitForPresence, isPresentAndDisplayed, waitUntilElementIsPresent, waitUntilElementIsVisible } from '../utilities'; -import { Header } from '../components'; -import { UploadFilesDialog } from '../components/dialog/upload-files-dialog'; - -export abstract class Page { - appRoot = 'app-root'; - - layout = this.byCss('app-shell'); - overlay = this.byCss('.cdk-overlay-container'); - snackBar = this.byCss(`[data-automation-id='adf-snackbar-message-content-action-button']`); - dialogContainer = this.byCss('.mat-dialog-container'); - - uploadFilesDialog = new UploadFilesDialog(); - - constructor(public url: string = '') {} - - protected byCss(css: string): ElementFinder { - return browser.element(by.css(css)); - } - - async load(relativeUrl: string = '') { - const hash = USE_HASH_STRATEGY ? '#' : ''; - const path = `${browser.baseUrl}${hash}${this.url}${relativeUrl}`; - return browser.get(path); - } - - async waitForApp(): Promise { - await waitForPresence(this.layout); - } - - async signOut(): Promise { - const header = new Header(); - await header.openMoreMenu(); - await header.menu.clickMenuItem('Sign out'); - await waitUntilElementIsPresent(browser.element(by.css('[class*="login-content"] input#username'))); - } - - async waitForDialog(): Promise { - await waitUntilElementIsVisible(this.dialogContainer); - } - - async isDialogOpen(): Promise { - return isPresentAndDisplayed(this.dialogContainer); - } - - async closeOpenDialogs(): Promise { - while (await this.isDialogOpen()) { - await Utils.pressEscape(); - } - } - - async refresh(): Promise { - await browser.refresh(); - await this.waitForApp(); - } - - async getSnackBarMessage(): Promise { - const elem = await waitElement(`[data-automation-id='adf-snackbar-message-content']`); - const attributeValue: string = await browser.executeScript(`return arguments[0].innerText`, elem); - return attributeValue || ''; - } - - async getSnackBarAction(): Promise { - let elem: WebElement; - try { - elem = await waitElement(`[data-automation-id='adf-snackbar-message-content-action-button']`); - } catch (e) { - return ''; - } - const attributeValue: string = await browser.executeScript(`return arguments[0].innerText`, elem); - return attributeValue || ''; - } - - async clickSnackBarAction(): Promise { - try { - const action = await waitElement(`[data-automation-id='adf-snackbar-message-content-action-button']`); - await action.click(); - } catch (e) { - console.error(e, '.......failed on click snack bar action.........'); - } - } - - async isLoggedIn(): Promise { - const url = await browser.driver.getCurrentUrl(); - return !url.includes(APP_ROUTES.LOGIN); - } -} diff --git a/projects/aca-testing-shared/src/pages/search-results-page.ts b/projects/aca-testing-shared/src/pages/search-results-page.ts deleted file mode 100755 index 5757a18e7e..0000000000 --- a/projects/aca-testing-shared/src/pages/search-results-page.ts +++ /dev/null @@ -1,36 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { BrowsingPage } from './browsing-page'; -import { SearchSortingPicker, SearchFilters } from '../components'; - -export class SearchResultsPage extends BrowsingPage { - root = this.byCss('aca-search-results'); - sortingPicker = new SearchSortingPicker('aca-search-results'); - filters = new SearchFilters('aca-search-results'); - - async waitForResults(): Promise { - await this.dataTable.waitForBody(); - } -} diff --git a/projects/aca-testing-shared/src/utilities/admin-actions.ts b/projects/aca-testing-shared/src/utilities/admin-actions.ts deleted file mode 100755 index 57243b8ccf..0000000000 --- a/projects/aca-testing-shared/src/utilities/admin-actions.ts +++ /dev/null @@ -1,52 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { PersonEntry, PeopleApi } from '@alfresco/js-api'; -import { PersonModel, SitesApi, UploadApi, NodesApi, Person, SharedLinksApi } from './repo-client/apis'; -import { UserActions } from './user-actions'; -import { browser } from 'protractor'; - -export class AdminActions extends UserActions { - sites: SitesApi = new SitesApi(); - upload: UploadApi = new UploadApi(); - nodes: NodesApi = new NodesApi(); - shared: SharedLinksApi = new SharedLinksApi(); - - async login(username?: string, password?: string) { - return super.login(username || browser.params.ADMIN_USERNAME, password || browser.params.ADMIN_PASSWORD); - } - - async createUser(user: PersonModel): Promise { - const person = new Person(user); - const peopleApi = new PeopleApi(this.alfrescoApi); - - await this.login(); - try { - return peopleApi.createPerson(person); - } catch (error) { - super.handleError('Admin Actions - createUser failed : ', error); - return null; - } - } -} diff --git a/projects/aca-testing-shared/src/utilities/browser-actions.ts b/projects/aca-testing-shared/src/utilities/browser-actions.ts deleted file mode 100644 index 597a179e91..0000000000 --- a/projects/aca-testing-shared/src/utilities/browser-actions.ts +++ /dev/null @@ -1,84 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { browser, ElementFinder, protractor } from 'protractor'; -import { waitUntilElementHasValue, waitUntilElementIsClickable, waitUntilElementIsVisible } from './browser-visibility'; - -export async function click(elementToClick: ElementFinder): Promise { - try { - await waitUntilElementIsVisible(elementToClick); - await waitUntilElementIsClickable(elementToClick); - await elementToClick.click(); - } catch (clickErr) { - await clickScript(elementToClick); - } -} - -export async function rightClick(elementFinder: ElementFinder): Promise { - await browser.actions().mouseMove(elementFinder).mouseDown().mouseMove(elementFinder).perform(); - await browser.actions().click(elementFinder, protractor.Button.RIGHT).perform(); -} - -async function clickScript(elementToClick: ElementFinder): Promise { - await browser.executeScript(`arguments[0].scrollIntoView();`, elementToClick); - await browser.executeScript(`arguments[0].click();`, elementToClick); -} - -export async function getInputValue(elementFinder: ElementFinder): Promise { - const present = await waitUntilElementIsVisible(elementFinder); - if (present) { - return browser.executeScript(`return arguments[0].value`, elementFinder); - } else { - console.error(`Get Input value ${elementFinder.locator().toString()} not present`); - return ''; - } -} - -export async function getUrl(url: string, timeout: number = 10000): Promise { - return browser.get(url, timeout); -} - -export async function clearSendKeys(elementFinder: ElementFinder, text: string = '', sleepTime: number = 0): Promise { - await click(elementFinder); - await elementFinder.sendKeys(''); - await elementFinder.clear(); - - if (sleepTime === 0) { - await elementFinder.sendKeys(text); - } else { - // eslint-disable-next-line @typescript-eslint/prefer-for-of - for (let i = 0; i < text.length; i++) { - await elementFinder.sendKeys(text[i]); - await browser.sleep(sleepTime); - } - } - - try { - if (text !== protractor.Key.SPACE && text !== protractor.Key.ENTER) { - await waitUntilElementHasValue(elementFinder, text, 1000); - } - } catch (e) { - console.info(`Set value different from the input`); - } -} diff --git a/projects/aca-testing-shared/src/utilities/browser-visibility.ts b/projects/aca-testing-shared/src/utilities/browser-visibility.ts deleted file mode 100644 index fae352d717..0000000000 --- a/projects/aca-testing-shared/src/utilities/browser-visibility.ts +++ /dev/null @@ -1,80 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { browser, ElementFinder, protractor } from 'protractor'; -import { falseIfMissing } from 'protractor/built/util'; - -export async function waitUntilElementIsVisible( - elementToCheck: ElementFinder, - waitTimeout: number = 10000, - message: string = 'Element is not visible' -): Promise { - return browser.wait(protractor.ExpectedConditions.visibilityOf(elementToCheck), waitTimeout, message + elementToCheck.locator()); -} - -export async function waitUntilElementIsNotVisible(elementToCheck: ElementFinder, waitTimeout: number = 10000): Promise { - return browser.wait( - protractor.ExpectedConditions.invisibilityOf(elementToCheck), - waitTimeout, - 'Element is Visible and it should not' + elementToCheck.locator() - ); -} - -export async function waitUntilElementIsClickable(elementToCheck: ElementFinder, waitTimeout: number = 10000): Promise { - return browser.wait( - protractor.ExpectedConditions.elementToBeClickable(elementToCheck), - waitTimeout, - 'Element is not Clickable ' + elementToCheck.locator() - ); -} - -export async function waitUntilElementIsPresent(elementToCheck: ElementFinder, waitTimeout: number = 10000): Promise { - return browser.wait(protractor.ExpectedConditions.presenceOf(elementToCheck), waitTimeout, 'Element is not present ' + elementToCheck.locator()); -} - -export async function waitUntilElementIsNotPresent(elementToCheck: ElementFinder, waitTimeout: number = 10000): Promise { - return browser.wait(protractor.ExpectedConditions.stalenessOf(elementToCheck), waitTimeout, 'Element is present ' + elementToCheck.locator()); -} - -function textToBePresentInElementValue(elementFinder: ElementFinder, text: string) { - const hasText = async () => - browser.executeScript(`return arguments[0].value`, elementFinder).then((actualText: string) => actualText.indexOf(text) > -1, falseIfMissing); - return protractor.ExpectedConditions.and(protractor.ExpectedConditions.presenceOf(elementFinder), hasText); -} - -export async function waitUntilElementHasValue(elementToCheck: ElementFinder, elementValue, waitTimeout: number = 10000): Promise { - return browser.wait( - textToBePresentInElementValue(elementToCheck, elementValue), - waitTimeout, - `Element doesn't have a value ${elementValue} ${elementToCheck.locator()}` - ); -} - -export async function waitUntilElementHasText(elementToCheck: ElementFinder, text, waitTimeout: number = 10000): Promise { - return browser.wait( - protractor.ExpectedConditions.textToBePresentInElement(elementToCheck, text), - waitTimeout, - `Element doesn't have the text ${text} ${elementToCheck.locator()}` - ); -} diff --git a/projects/aca-testing-shared/src/utilities/index.ts b/projects/aca-testing-shared/src/utilities/index.ts deleted file mode 100644 index c16c1b77af..0000000000 --- a/projects/aca-testing-shared/src/utilities/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -export * from './repo-client/apis'; -export * from './repo-client/repo-client'; -export * from './admin-actions'; -export * from './user-actions'; -export * from './utils'; -export * from './browser-visibility'; -export * from './browser-actions'; -export * from './api'; -export * from './logger'; -export * from './test-element'; diff --git a/projects/aca-testing-shared/src/utilities/repo-client/apis/favorites/favorites-api.ts b/projects/aca-testing-shared/src/utilities/repo-client/apis/favorites/favorites-api.ts deleted file mode 100755 index 72b4b71a80..0000000000 --- a/projects/aca-testing-shared/src/utilities/repo-client/apis/favorites/favorites-api.ts +++ /dev/null @@ -1,156 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { RepoApi } from '../repo-api'; -import { Utils } from '../../../utils'; -import { FavoritesApi as AdfFavoritesApi, SitesApi as AdfSiteApi, FavoriteEntry } from '@alfresco/js-api'; - -export class FavoritesApi extends RepoApi { - favoritesApi = new AdfFavoritesApi(this.alfrescoJsApi); - sitesApi = new AdfSiteApi(this.alfrescoJsApi); - - constructor(username?: string, password?: string) { - super(username, password); - } - - async addFavoriteById(nodeType: 'file' | 'folder' | 'site', id: string): Promise { - let guid; - try { - await this.apiAuth(); - if (nodeType === 'site') { - guid = (await this.sitesApi.getSite(id)).entry.guid; - } else { - guid = id; - } - const data = { - target: { - [nodeType]: { - guid: guid - } - } - }; - return await this.favoritesApi.createFavorite('-me-', data); - } catch (error) { - this.handleError(`FavoritesApi addFavoriteById : catch : `, error); - return null; - } - } - - async addFavoritesByIds(nodeType: 'file' | 'folder' | 'site', ids: string[]): Promise { - const favorites: FavoriteEntry[] = []; - try { - if (ids && ids.length > 0) { - for (const id of ids) { - const favorite = await this.addFavoriteById(nodeType, id); - favorites.push(favorite); - } - } - } catch (error) { - this.handleError(`FavoritesApi addFavoritesByIds : catch : `, error); - } - return favorites; - } - - private async getFavorites() { - try { - await this.apiAuth(); - return await this.favoritesApi.listFavorites(this.username); - } catch (error) { - this.handleError(`FavoritesApi getFavorites : catch : `, error); - return null; - } - } - - async getFavoritesTotalItems(): Promise { - try { - await this.apiAuth(); - return (await this.favoritesApi.listFavorites(this.username)).list.pagination.totalItems; - } catch (error) { - this.handleError(`FavoritesApi getFavoritesTotalItems : catch : `, error); - return -1; - } - } - - async isFavorite(nodeId: string) { - try { - return JSON.stringify((await this.getFavorites()).list.entries).includes(nodeId); - } catch (error) { - this.handleError(`FavoritesApi isFavorite : catch : `, error); - return null; - } - } - - async isFavoriteWithRetry(nodeId: string, data: { expect: boolean }) { - try { - const favorite = async () => { - let isFavorite = await this.isFavorite(nodeId); - if (isFavorite !== data.expect) { - return Promise.reject(isFavorite); - } else { - return Promise.resolve(isFavorite); - } - }; - return await Utils.retryCall(favorite); - } catch { - return false; - } - } - - private async removeFavoriteById(nodeId: string) { - try { - await this.apiAuth(); - return await this.favoritesApi.deleteFavorite('-me-', nodeId); - } catch (error) { - this.handleError(`FavoritesApi removeFavoriteById : catch : `, error); - } - } - - async removeFavoritesByIds(ids: string[]) { - try { - return await ids.reduce(async (previous, current) => { - await previous; - await this.removeFavoriteById(current); - }, Promise.resolve()); - } catch (error) { - this.handleError(`FavoritesApi removeFavoritesByIds : catch : `, error); - } - } - - async waitForApi(data: { expect: number }) { - try { - const favoriteFiles = async () => { - const totalItems = await this.getFavoritesTotalItems(); - if (totalItems !== data.expect) { - return Promise.reject(totalItems); - } else { - return Promise.resolve(totalItems); - } - }; - return await Utils.retryCall(favoriteFiles); - } catch (error) { - console.error(`FavoritesApi waitForApi : catch : `); - console.error(`\tExpected: ${data.expect} items, but found ${error}`); - } - } -} diff --git a/projects/aca-testing-shared/src/utilities/repo-client/apis/index.ts b/projects/aca-testing-shared/src/utilities/repo-client/apis/index.ts deleted file mode 100644 index 40d73271f3..0000000000 --- a/projects/aca-testing-shared/src/utilities/repo-client/apis/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -export * from './favorites/favorites-api'; -export * from './nodes/node-content-tree'; -export * from './nodes/nodes-api'; -export * from './people/people-api-models'; -export * from './queries/queries-api'; -export * from './search/search-api'; -export * from './shared-links/shared-links-api'; -export * from './sites/sites-api'; -export * from './upload/upload-api'; -export * from './repo-api'; diff --git a/projects/aca-testing-shared/src/utilities/repo-client/apis/nodes/node-content-tree.ts b/projects/aca-testing-shared/src/utilities/repo-client/apis/nodes/node-content-tree.ts deleted file mode 100755 index 0744086235..0000000000 --- a/projects/aca-testing-shared/src/utilities/repo-client/apis/nodes/node-content-tree.ts +++ /dev/null @@ -1,96 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -const NODE_TYPE_FILE = 'cm:content'; -const NODE_TYPE_FOLDER = 'cm:folder'; -const NODE_TITLE = 'cm:title'; -const NODE_DESCRIPTION = 'cm:description'; - -export interface NodeContentTree { - name?: string; - files?: string[]; - folders?: (string | NodeContentTree)[]; - title?: string; - description?: string; -} - -export interface NodeBodyCreate { - name: string; - nodeType: string; - relativePath: string; - aspectNames?: string[]; - properties?: any[]; -} - -export function flattenNodeContentTree(content: NodeContentTree, relativePath: string = '/'): NodeBodyCreate[] { - const { name, files, folders, title, description } = content; - const aspectNames: string[] = ['cm:versionable']; - let data: NodeBodyCreate[] = []; - let properties: any; - - properties = { - [NODE_TITLE]: title, - [NODE_DESCRIPTION]: description - }; - - if (name) { - data = data.concat([ - { - nodeType: NODE_TYPE_FOLDER, - name, - relativePath, - properties - } - ]); - - relativePath = relativePath === '/' ? `/${name}` : `${relativePath}/${name}`; - } - - if (folders) { - const foldersData: NodeBodyCreate[] = folders - .map((folder: string | NodeContentTree): NodeBodyCreate[] => { - const folderData: NodeContentTree = typeof folder === 'string' ? { name: folder } : folder; - - return flattenNodeContentTree(folderData, relativePath); - }) - .reduce((nodesData: NodeBodyCreate[], folderData: NodeBodyCreate[]) => nodesData.concat(folderData), []); - - data = data.concat(foldersData); - } - - if (files) { - const filesData: NodeBodyCreate[] = files.map( - (filename: string): NodeBodyCreate => ({ - nodeType: NODE_TYPE_FILE, - name: filename, - relativePath, - aspectNames - }) - ); - - data = data.concat(filesData); - } - - return data; -} diff --git a/projects/aca-testing-shared/src/utilities/repo-client/apis/nodes/nodes-api.ts b/projects/aca-testing-shared/src/utilities/repo-client/apis/nodes/nodes-api.ts deleted file mode 100755 index 270628f28a..0000000000 --- a/projects/aca-testing-shared/src/utilities/repo-client/apis/nodes/nodes-api.ts +++ /dev/null @@ -1,449 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { RepoApi } from '../repo-api'; -import { flattenNodeContentTree, NodeContentTree } from './node-content-tree'; -import { NodeChildAssociationPaging, NodeEntry, NodesApi as AdfNodeApi } from '@alfresco/js-api'; -import { Utils } from '../../../../utilities/utils'; - -export class NodesApi extends RepoApi { - private nodesApi = new AdfNodeApi(this.alfrescoJsApi); - - constructor(username?: string, password?: string) { - super(username, password); - } - - async getNodeByPath(relativePath: string = '/', parentFolderId: string = '-my-'): Promise { - try { - await this.apiAuth(); - return await this.nodesApi.getNode(parentFolderId, { relativePath }); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.getNodeByPath.name}`, error); - return null; - } - } - - async getNodeById(id: string): Promise { - try { - await this.apiAuth(); - return await this.nodesApi.getNode(id); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.getNodeById.name}`, error); - return null; - } - } - - async getNodeIdFromParent(name: string, parentId: string): Promise { - try { - const children = (await this.getNodeChildren(parentId)).list.entries; - return children.find((elem) => elem.entry.name === name).entry.id || ''; - } catch (error) { - this.handleError(`${this.constructor.name} ${this.getNodeIdFromParent.name}`, error); - return ''; - } - } - - async getNodeDescription(name: string, parentId: string): Promise { - try { - const children = (await this.getNodeChildren(parentId)).list.entries; - return children.find((elem) => elem.entry.name === name).entry.properties['cm:description']; - } catch (error) { - this.handleError(`${this.constructor.name} ${this.getNodeDescription.name}`, error); - return ''; - } - } - - async getNodeProperty(nodeId: string, property: string): Promise { - try { - const node = await this.getNodeById(nodeId); - return (node.entry.properties && node.entry.properties[property]) || ''; - } catch (error) { - this.handleError(`${this.constructor.name} ${this.getNodeProperty.name}`, error); - return ''; - } - } - - async getFileVersionType(nodeId: string): Promise { - try { - const prop = await this.getNodeProperty(nodeId, 'cm:versionType'); - return prop || ''; - } catch (error) { - this.handleError(`${this.constructor.name} ${this.getFileVersionType.name}`, error); - return ''; - } - } - - async getFileVersionLabel(nodeId: string): Promise { - try { - const prop = await this.getNodeProperty(nodeId, 'cm:versionLabel'); - return prop || ''; - } catch (error) { - this.handleError(`${this.constructor.name} ${this.getFileVersionLabel.name}`, error); - return ''; - } - } - - async getSharedId(nodeId: string): Promise { - try { - const sharedId = await this.getNodeProperty(nodeId, 'qshare:sharedId'); - return sharedId || ''; - } catch (error) { - this.handleError(`${this.constructor.name} ${this.getSharedId.name}`, error); - return ''; - } - } - - async getSharedExpiryDate(nodeId: string): Promise { - try { - const expiryDate = await this.getNodeProperty(nodeId, 'qshare:expiryDate'); - return expiryDate || ''; - } catch (error) { - this.handleError(`${this.constructor.name} ${this.getSharedExpiryDate.name}`, error); - return ''; - } - } - - async isFileShared(nodeId: string): Promise { - try { - const sharedId = await this.getSharedId(nodeId); - return sharedId !== ''; - } catch (error) { - this.handleError(`${this.constructor.name} ${this.isFileShared.name}`, error); - return null; - } - } - - async deleteNodeById(id: string, permanent: boolean = true): Promise { - try { - await this.apiAuth(); - await this.nodesApi.deleteNode(id, { permanent }); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.deleteNodeById.name}`, error); - } - } - - async deleteNodeByPath(path: string, permanent: boolean = true, parentFolderId?: string): Promise { - try { - const id = (await this.getNodeByPath(path, parentFolderId)).entry.id; - await this.deleteNodeById(id, permanent); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.deleteNodeByPath.name}`, error); - } - } - - async deleteNodes(names: string[], relativePath: string = '', permanent: boolean = true): Promise { - try { - await names.reduce(async (previous, current) => { - await previous; - return await this.deleteNodeByPath(`${relativePath}/${current}`, permanent); - }, Promise.resolve()); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.deleteNodes.name}`, error); - } - } - - async deleteNodesById(ids: string[], permanent: boolean = true): Promise { - try { - await this.apiAuth(); - await this.nodesApi.deleteNodes(ids, { permanent }); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.deleteNodesById.name}`, error); - } - } - - private async getNodeChildren(nodeId: string): Promise { - try { - const opts = { - include: ['properties'] - }; - await this.apiAuth(); - return await this.nodesApi.listNodeChildren(nodeId, opts); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.getNodeChildren.name}`, error); - return null; - } - } - - async deleteNodeChildren(parentId: string, exceptNodesNamed?: string[]): Promise { - try { - const listEntries = (await this.getNodeChildren(parentId)).list.entries; - let nodeIds: string[]; - if (exceptNodesNamed) { - nodeIds = listEntries.filter((entries) => !exceptNodesNamed.includes(entries.entry.name)).map((entries) => entries.entry.id); - } else { - nodeIds = listEntries.map((entries) => entries.entry.id); - } - await this.deleteNodesById(nodeIds); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.deleteNodeChildren.name}`, error); - } - } - - private async createImageNode(name: string, parentId: string = '-my-', title: string = '', description: string = ''): Promise { - const imageProps = { - 'exif:pixelXDimension': 1000, - 'exif:pixelYDimension': 1200 - }; - try { - return await this.createNode('cm:content', name, parentId, title, description, imageProps); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.createImageNode.name}`, error); - return null; - } - } - - private async createNode( - nodeType: string, - name: string, - parentId: string = '-my-', - title: string = '', - description: string = '', - imageProps: any = null, - author: string = '', - majorVersion: boolean = true, - aspectNames: string[] = null - ): Promise { - if (!aspectNames) { - aspectNames = ['cm:versionable']; // workaround for REPO-4772 - } - const nodeBody = { - name, - nodeType, - properties: { - 'cm:title': title, - 'cm:description': description, - 'cm:author': author - }, - aspectNames - }; - if (imageProps) { - nodeBody.properties = Object.assign(nodeBody.properties, imageProps); - } - - try { - await this.apiAuth(); - return await this.nodesApi.createNode(parentId, nodeBody, { - majorVersion - }); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.createNode.name}`, error); - return null; - } - } - - async createFile( - name: string, - parentId: string = '-my-', - title: string = '', - description: string = '', - author: string = '', - majorVersion: boolean = true, - aspectNames: string[] = null - ): Promise { - try { - return await this.createNode('cm:content', name, parentId, title, description, null, author, majorVersion, aspectNames); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.createFile.name}`, error); - return null; - } - } - - async createImage(name: string, parentId: string = '-my-', title: string = '', description: string = ''): Promise { - try { - return await this.createImageNode(name, parentId, title, description); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.createImage.name}`, error); - return null; - } - } - - async createFolder( - name: string, - parentId: string = '-my-', - title: string = '', - description: string = '', - author: string = '', - aspectNames: string[] = null - ): Promise { - try { - return await this.createNode('cm:folder', name, parentId, title, description, null, author, null, aspectNames); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.createFolder.name}`, error); - return null; - } - } - - async createContent(content: NodeContentTree, relativePath: string = '/'): Promise { - try { - await this.apiAuth(); - return await this.nodesApi.createNode('-my-', flattenNodeContentTree(content, relativePath) as any); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.createContent.name}`, error); - } - } - - async createFolders(names: string[], relativePath: string = '/'): Promise { - try { - return await this.createContent({ folders: names }, relativePath); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.createFolders.name}`, error); - } - } - - async createFiles(names: string[], relativePath: string = '/'): Promise { - try { - return await this.createContent({ files: names }, relativePath); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.createFiles.name}`, error); - } - } - - private async addAspects(nodeId: string, aspectNames: string[]): Promise { - try { - await this.apiAuth(); - return this.nodesApi.updateNode(nodeId, { aspectNames }); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.addAspects.name}`, error); - return null; - } - } - - async createFolderLink(originalNodeId: string, destinationId: string): Promise { - const name = (await this.getNodeById(originalNodeId)).entry.name; - const nodeBody = { - name: `Link to ${name}.url`, - nodeType: 'app:folderlink', - properties: { - 'cm:title': `Link to ${name}.url`, - 'cm:destination': originalNodeId, - 'cm:description': `Link to ${name}.url`, - 'app:icon': 'space-icon-link' - } - }; - - try { - await this.apiAuth(); - const link = await this.nodesApi.createNode(destinationId, nodeBody); - await this.addAspects(originalNodeId, ['app:linked']); - return link; - } catch (error) { - this.handleError(`${this.constructor.name} ${this.createFolderLink.name}`, error); - return null; - } - } - - async updateNodeContent( - nodeId: string, - content: string, - majorVersion: boolean = true, - comment?: string, - newName?: string - ): Promise { - try { - const opts = { - majorVersion, - comment, - name: newName - }; - await this.apiAuth(); - return await this.nodesApi.updateNodeContent(nodeId, content, opts); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.updateNodeContent.name}`, error); - return null; - } - } - - async setGranularPermission(nodeId: string, inheritPermissions: boolean = false, username: string, role: string): Promise { - const data = { - permissions: { - isInheritanceEnabled: inheritPermissions, - locallySet: [ - { - authorityId: username, - name: role - } - ] - } - }; - - try { - await this.apiAuth(); - return await this.nodesApi.updateNode(nodeId, data); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.setGranularPermission.name}`, error); - return null; - } - } - - private async getLockType(nodeId: string): Promise { - try { - const lockType = await this.getNodeProperty(nodeId, 'cm:lockType'); - return lockType || ''; - } catch (error) { - this.handleError(`${this.constructor.name} ${this.getLockType.name}`, error); - return ''; - } - } - - async isFileLockedWrite(nodeId: string): Promise { - try { - return (await this.getLockType(nodeId)) === 'WRITE_LOCK'; - } catch (error) { - this.handleError(`${this.constructor.name} ${this.isFileLockedWrite.name}`, error); - return null; - } - } - - async isFileLockedWriteWithRetry(nodeId: string, expect: boolean): Promise { - const data = { - expect: expect, - retry: 5 - }; - let isLocked = false; - try { - const locked = async () => { - isLocked = (await this.getLockType(nodeId)) === 'WRITE_LOCK'; - if (isLocked !== data.expect) { - return Promise.reject(isLocked); - } else { - return Promise.resolve(isLocked); - } - }; - return await Utils.retryCall(locked, data.retry); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.isFileLockedWriteWithRetry.name}`, error); - } - return isLocked; - } - - async isFileLockedByName(fileName: string, parentId: string): Promise { - try { - const id = await this.getNodeIdFromParent(fileName, parentId); - return await this.isFileLockedWrite(id); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.isFileLockedByName.name}`, error); - return null; - } - } -} diff --git a/projects/aca-testing-shared/src/utilities/repo-client/apis/people/people-api-models.ts b/projects/aca-testing-shared/src/utilities/repo-client/apis/people/people-api-models.ts deleted file mode 100755 index 38a3bd6d51..0000000000 --- a/projects/aca-testing-shared/src/utilities/repo-client/apis/people/people-api-models.ts +++ /dev/null @@ -1,52 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -export interface PersonModel { - username?: string; - password?: string; - firstName?: string; - lastName?: string; - email?: string; - enabled?: boolean; - properties?: any; -} - -export class Person { - id: string; - password: string; - firstName: string; - lastName: string; - email: string; - enabled: boolean; - properties: any; - - constructor(user: PersonModel) { - this.id = user.username; - this.password = user.password || user.username; - this.firstName = user.firstName || user.username; - this.lastName = user.lastName || user.username; - this.email = user.email || `${user.username}@alfresco.com`; - this.enabled = user.enabled || true; - } -} diff --git a/projects/aca-testing-shared/src/utilities/repo-client/apis/queries/queries-api.ts b/projects/aca-testing-shared/src/utilities/repo-client/apis/queries/queries-api.ts deleted file mode 100755 index 9d9e7931ac..0000000000 --- a/projects/aca-testing-shared/src/utilities/repo-client/apis/queries/queries-api.ts +++ /dev/null @@ -1,70 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { RepoApi } from '../repo-api'; -import { Utils } from '../../../utils'; -import { QueriesApi as AdfQueriesApi } from '@alfresco/js-api'; - -export class QueriesApi extends RepoApi { - queriesApi = new AdfQueriesApi(this.alfrescoJsApi); - - constructor(username?: string, password?: string) { - super(username, password); - } - - private async findSitesTotalItems(searchTerm: string): Promise { - try { - await this.apiAuth(); - - const opts = { - term: searchTerm, - fields: ['title'] - }; - - const sites = await this.queriesApi.findSites(searchTerm, opts); - return sites.list.pagination.totalItems; - } catch (error) { - this.handleError(`QueriesApi findSitesTotalItems : catch :`, error); - return -1; - } - } - - async waitForSites(searchTerm: string, data: { expect: number }) { - try { - const sites = async () => { - const totalItems = await this.findSitesTotalItems(searchTerm); - if (totalItems !== data.expect) { - return Promise.reject(totalItems); - } else { - return Promise.resolve(totalItems); - } - }; - - return await Utils.retryCall(sites); - } catch (error) { - console.error(`QueriesApi waitForSites : catch : `); - console.error(`\tExpected: ${data.expect} items, but found ${error}`); - } - } -} diff --git a/projects/aca-testing-shared/src/utilities/repo-client/apis/repo-api.ts b/projects/aca-testing-shared/src/utilities/repo-client/apis/repo-api.ts deleted file mode 100644 index af693635fc..0000000000 --- a/projects/aca-testing-shared/src/utilities/repo-client/apis/repo-api.ts +++ /dev/null @@ -1,54 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { browser } from 'protractor'; -import { AlfrescoApi } from '@alfresco/js-api'; - -export abstract class RepoApi { - alfrescoJsApi = new AlfrescoApi(); - - protected constructor(public username: string = browser.params.ADMIN_USERNAME, private password: string = browser.params.ADMIN_PASSWORD) { - this.alfrescoJsApi.setConfig(browser.params.config); - } - - apiAuth(): Promise { - return this.alfrescoJsApi.login(this.username, this.password); - } - - protected handleError(message: string, response: any) { - console.error(`\n--- ${message} error :`); - console.error('\t>>> username: ', this.username); - console.error('\t>>> JSON: ', JSON.stringify(browser.params.config)); - if (response.status && response.response) { - try { - console.error('\t>>> Status: ', response.status); - console.error('\t>>> Text: ', response.response.text); - console.error('\t>>> Method: ', response.response.error.method); - console.error('\t>>> Path: ', response.response.error.path); - } catch { - console.error('\t>>> ', response); - } - } else console.error('\t>>> ', response); - } -} diff --git a/projects/aca-testing-shared/src/utilities/repo-client/apis/search/search-api.ts b/projects/aca-testing-shared/src/utilities/repo-client/apis/search/search-api.ts deleted file mode 100755 index 60fc39eeb9..0000000000 --- a/projects/aca-testing-shared/src/utilities/repo-client/apis/search/search-api.ts +++ /dev/null @@ -1,122 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { RepoApi } from '../repo-api'; -import { Utils } from '../../../utils'; -import { waitForApi } from '../../../api'; -import { SearchApi as AdfSearchApi } from '@alfresco/js-api'; - -export class SearchApi extends RepoApi { - searchApi = new AdfSearchApi(this.alfrescoJsApi); - - constructor(username?: string, password?: string) { - super(username, password); - } - - private async queryRecentFiles(username: string) { - const data = { - query: { - query: '*', - language: 'afts' - }, - filterQueries: [ - { query: `cm:modified:[NOW/DAY-30DAYS TO NOW/DAY+1DAY]` }, - { query: `cm:modifier:${username} OR cm:creator:${username}` }, - { query: `TYPE:"content" AND -TYPE:"app:filelink" AND -TYPE:"fm:post"` } - ] - }; - - try { - await this.apiAuth(); - return this.searchApi.search(data); - } catch (error) { - this.handleError(`SearchApi queryRecentFiles : catch : `, error); - return null; - } - } - - async getTotalItems(username: string): Promise { - try { - return (await this.queryRecentFiles(username)).list.pagination.totalItems; - } catch (error) { - this.handleError(`SearchApi getTotalItems : catch : `, error); - return -1; - } - } - - private async queryNodesNames(searchTerm: string) { - const data = { - query: { - query: `cm:name:\"${searchTerm}*\"`, - language: 'afts' - }, - filterQueries: [{ query: `+TYPE:'cm:folder' OR +TYPE:'cm:content'` }] - }; - - try { - await this.apiAuth(); - return this.searchApi.search(data); - } catch (error) { - this.handleError(`SearchApi queryNodesNames : catch : `, error); - return null; - } - } - - async waitForApi(username: string, data: { expect: number }) { - try { - const recentFiles = async () => { - const totalItems = await this.getTotalItems(username); - if (totalItems !== data.expect) { - return Promise.reject(totalItems); - } else { - return Promise.resolve(totalItems); - } - }; - - return await Utils.retryCall(recentFiles); - } catch (error) { - console.error(`SearchApi waitForApi : catch : `); - console.error(`\tExpected: ${data.expect} items, but found ${error}`); - } - } - - async waitForNodes(searchTerm: string, data: { expect: number }) { - const predicate = (totalItems: number) => totalItems === data.expect; - - const apiCall = async () => { - try { - return (await this.queryNodesNames(searchTerm)).list.pagination.totalItems; - } catch (error) { - return 0; - } - }; - - try { - await waitForApi(apiCall, predicate, 30, 2500); - } catch (error) { - console.error(`SearchApi waitForNodes : catch : `); - console.error(`\tExpected: ${data.expect} items, but found ${error}`); - } - } -} diff --git a/projects/aca-testing-shared/src/utilities/repo-client/apis/shared-links/shared-links-api.ts b/projects/aca-testing-shared/src/utilities/repo-client/apis/shared-links/shared-links-api.ts deleted file mode 100755 index eba88fca80..0000000000 --- a/projects/aca-testing-shared/src/utilities/repo-client/apis/shared-links/shared-links-api.ts +++ /dev/null @@ -1,94 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { RepoApi } from '../repo-api'; -import { Utils } from '../../../utils'; -import { SharedlinksApi as AdfSharedlinksApi, SharedLinkEntry, SharedLinkPaging } from '@alfresco/js-api'; - -export class SharedLinksApi extends RepoApi { - sharedlinksApi = new AdfSharedlinksApi(this.alfrescoJsApi); - - constructor(username?: string, password?: string) { - super(username, password); - } - - async shareFileById(id: string, expireDate?: Date): Promise { - try { - await this.apiAuth(); - const data = { - nodeId: id, - expiresAt: expireDate - }; - return await this.sharedlinksApi.createSharedLink(data); - } catch (error) { - this.handleError(`SharedLinksApi shareFileById : catch : `, error); - return null; - } - } - - async shareFilesByIds(ids: string[]): Promise { - const sharedLinks: SharedLinkEntry[] = []; - try { - if (ids && ids.length > 0) { - for (const id of ids) { - const sharedLink = await this.shareFileById(id); - sharedLinks.push(sharedLink); - } - } - } catch (error) { - this.handleError(`SharedLinksApi shareFilesByIds : catch : `, error); - } - return sharedLinks; - } - - private async getSharedLinks(maxItems: number = 250): Promise { - try { - await this.apiAuth(); - const opts = { - maxItems - }; - return await this.sharedlinksApi.listSharedLinks(opts); - } catch (error) { - this.handleError(`SharedLinksApi getSharedLinks : catch : `, error); - return null; - } - } - - async waitForFilesToBeShared(filesIds: string[]): Promise { - const sharedFile = async () => { - const sharedFiles = (await this.getSharedLinks()).list.entries.map((link) => link.entry.nodeId); - const foundItems = filesIds.every((id) => sharedFiles.includes(id)); - if (foundItems) { - return Promise.resolve(foundItems); - } else { - return Promise.reject(foundItems); - } - }; - - return Utils.retryCall(sharedFile).catch((error) => { - console.error(`SharedLinksApi waitForFilesToBeShared : catch : ${error}`); - console.error(`\tWait timeout reached waiting for files to be shared`); - }); - } -} diff --git a/projects/aca-testing-shared/src/utilities/repo-client/apis/sites/sites-api.ts b/projects/aca-testing-shared/src/utilities/repo-client/apis/sites/sites-api.ts deleted file mode 100755 index fb5ec5de89..0000000000 --- a/projects/aca-testing-shared/src/utilities/repo-client/apis/sites/sites-api.ts +++ /dev/null @@ -1,150 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { RepoApi } from '../repo-api'; -import { SiteBodyCreate, SiteMembershipBodyUpdate, SiteMembershipBodyCreate, SiteEntry, SitesApi as AdfSiteApi } from '@alfresco/js-api'; -import { SITE_VISIBILITY } from '../../../../configs'; -import { Utils } from '../../../utils'; - -export class SitesApi extends RepoApi { - sitesApi = new AdfSiteApi(this.alfrescoJsApi); - - constructor(username?: string, password?: string) { - super(username, password); - } - - async getSite(siteId: string) { - try { - await this.apiAuth(); - return await this.sitesApi.getSite(siteId); - } catch (error) { - this.handleError(`SitesApi getSite : catch : `, error); - return null; - } - } - - async getDocLibId(siteId: string): Promise { - try { - await this.apiAuth(); - return (await this.sitesApi.listSiteContainers(siteId)).list.entries[0].entry.id; - } catch (error) { - this.handleError(`SitesApi getDocLibId : catch : `, error); - return null; - } - } - - async createSite(title: string, visibility?: string, description?: string, siteId?: string): Promise { - const site = { - title, - visibility: visibility || SITE_VISIBILITY.PUBLIC, - description: description, - id: siteId || title - } as SiteBodyCreate; - - try { - await this.apiAuth(); - return await this.sitesApi.createSite(site); - } catch (error) { - this.handleError(`SitesApi createSite : catch : `, error); - return null; - } - } - - async deleteSite(siteId: string, permanent: boolean = true) { - try { - await this.apiAuth(); - return await this.sitesApi.deleteSite(siteId, { permanent }); - } catch (error) { - this.handleError(`SitesApi deleteSite : catch : `, error); - } - } - - async deleteSites(siteIds: string[], permanent: boolean = true) { - try { - if (siteIds && siteIds.length > 0) { - await this.apiAuth(); - - for (const siteId of siteIds) { - await this.sitesApi.deleteSite(siteId, { permanent }); - } - } - } catch (error) { - this.handleError(`SitesApi deleteSites : catch : `, error); - } - } - - async updateSiteMember(siteId: string, userId: string, role: string) { - const siteRole = { - role: role - } as SiteMembershipBodyUpdate; - - try { - await this.apiAuth(); - return await this.sitesApi.updateSiteMembership(siteId, userId, siteRole); - } catch (error) { - this.handleError(`SitesApi updateSiteMember : catch : `, error); - return null; - } - } - - async addSiteMember(siteId: string, userId: string, role: string) { - const memberBody = { - id: userId, - role: role - } as SiteMembershipBodyCreate; - - try { - await this.apiAuth(); - return await this.sitesApi.createSiteMembership(siteId, memberBody); - } catch (error) { - if (error.status === 409) { - return this.updateSiteMember(siteId, userId, role); - } else { - this.handleError(`SitesApi addSiteMember : catch : `, error); - return null; - } - } - } - - async waitForSitesToBeCreated(sitesIds: string[]) { - try { - const site = async () => { - await this.apiAuth(); - const sites = await this.sitesApi.listSiteMembershipsForPerson(this.username); - const sitesList = sites.list.entries.map((link) => link.entry.id); - const foundItems = sitesIds.every((id) => sitesList.includes(id)); - if (foundItems) { - return Promise.resolve(foundItems); - } else { - return Promise.reject(foundItems); - } - }; - - return await Utils.retryCall(site); - } catch (error) { - console.error(`SitesApi waitForSitesToBeCreated : catch : ${error}`); - console.error(`\tWait timeout reached waiting for sites to be created`); - } - } -} diff --git a/projects/aca-testing-shared/src/utilities/repo-client/apis/upload/upload-api.ts b/projects/aca-testing-shared/src/utilities/repo-client/apis/upload/upload-api.ts deleted file mode 100644 index c6406653c5..0000000000 --- a/projects/aca-testing-shared/src/utilities/repo-client/apis/upload/upload-api.ts +++ /dev/null @@ -1,74 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { RepoApi } from '../repo-api'; -import { NodeBodyCreate, UploadApi as AdfUploadApi } from '@alfresco/js-api'; -import { browser } from 'protractor'; -import * as fs from 'fs'; - -export class UploadApi extends RepoApi { - private upload = new AdfUploadApi(this.alfrescoJsApi); - private e2eRootPath = browser.params.e2eRootPath; - - constructor(username?: string, password?: string) { - super(username, password); - } - - async uploadFile(fileName: string, parentFolderId: string = '-my-') { - const file = fs.createReadStream(`${this.e2eRootPath}/resources/test-files/${fileName}`); - const opts = { - name: fileName, - nodeType: 'cm:content' - }; - - try { - await this.apiAuth(); - return await this.upload.uploadFile(file, '', parentFolderId, null, opts); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.uploadFile.name}`, error); - } - } - - async uploadFileWithRename(fileName: string, parentId: string = '-my-', newName: string, title: string = '', description: string = '') { - const file = fs.createReadStream(`${this.e2eRootPath}/resources/test-files/${fileName}`); - const nodeProps = { - properties: { - 'cm:title': title, - 'cm:description': description - } - }; - - const opts = { - name: newName, - nodeType: 'cm:content' - }; - - try { - await this.apiAuth(); - return await this.upload.uploadFile(file, '', parentId, nodeProps as NodeBodyCreate, opts); - } catch (error) { - this.handleError(`${this.constructor.name} ${this.uploadFileWithRename.name}`, error); - } - } -} diff --git a/projects/aca-testing-shared/src/utilities/repo-client/repo-client.ts b/projects/aca-testing-shared/src/utilities/repo-client/repo-client.ts deleted file mode 100755 index dc7e750384..0000000000 --- a/projects/aca-testing-shared/src/utilities/repo-client/repo-client.ts +++ /dev/null @@ -1,81 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { browser } from 'protractor'; -import { NodesApi, SitesApi, FavoritesApi, QueriesApi, SharedLinksApi, SearchApi, UploadApi } from './apis'; -import { AlfrescoApi } from '@alfresco/js-api'; - -/** - * @deprecated Use {AdminActions} or {UserActions} instead. - */ -export class RepoClient { - alfrescoApi: AlfrescoApi; - - constructor(private username: string = browser.params.ADMIN_USERNAME, private password: string = browser.params.ADMIN_PASSWORD) { - this.alfrescoApi = new AlfrescoApi(); - this.alfrescoApi.setConfig(browser.params.config); - } - - apiAuth(): Promise { - return this.alfrescoApi.login(this.username, this.password); - } - - get nodes(): NodesApi { - return new NodesApi(this.username, this.password); - } - - get sites(): SitesApi { - return new SitesApi(this.username, this.password); - } - - get favorites(): FavoritesApi { - return new FavoritesApi(this.username, this.password); - } - - get shared(): SharedLinksApi { - return new SharedLinksApi(this.username, this.password); - } - - get search(): SearchApi { - return new SearchApi(this.username, this.password); - } - - get queries(): QueriesApi { - return new QueriesApi(this.username, this.password); - } - - get upload(): UploadApi { - return new UploadApi(this.username, this.password); - } - - async createFolder(name: string, parentId?: string): Promise { - const response = await this.nodes.createFolder(name, parentId); - return response.entry.id; - } - - async createFile(name: string, parentId?: string): Promise { - const response = await this.nodes.createFile(name, parentId); - return response.entry.id; - } -} diff --git a/projects/aca-testing-shared/src/utilities/test-element.ts b/projects/aca-testing-shared/src/utilities/test-element.ts deleted file mode 100644 index 7c1b400ecb..0000000000 --- a/projects/aca-testing-shared/src/utilities/test-element.ts +++ /dev/null @@ -1,155 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { by, element, ElementFinder, $, browser } from 'protractor'; -import { clearSendKeys, click } from './browser-actions'; -import { waitUntilElementIsNotVisible, waitUntilElementIsPresent, waitUntilElementIsVisible } from './browser-visibility'; - -async function getText(elementFinder: ElementFinder): Promise { - const present = await waitUntilElementIsVisible(elementFinder); - - if (present) { - let text = await elementFinder.getText(); - - if (text === '') { - // DO NOT REMOVE BUG sometime wrongly return empty text for cdk elements - console.info(`Use backup get text script`); - - text = await browser.executeScript(`return arguments[0].textContent`, elementFinder); - return text?.trim(); - } - - return text; - } else { - console.error(`Get Text ${elementFinder.locator().toString()} not present`); - return ''; - } -} - -/** - * Provides a wrapper for the most common operations with the page elements. - */ -export class TestElement { - constructor(public elementFinder: ElementFinder) {} - - /** - * Create a new instance with the element located by the id - * - * @param id The id of the element - * @returns test element wrapper - */ - static byId(id: string): TestElement { - return new TestElement(element(by.id(id))); - } - - /** - * Create a new instance with the element located by the CSS class name - * - * @param selector The CSS class name to lookup - * @returns test element wrapper - */ - static byCss(selector: string): TestElement { - return new TestElement($(selector)); - } - - /** - * Create a new instance with the element that contains specific text - * - * @param selector the CSS selector - * @param text the text within the target element - * @returns test element wrapper - */ - static byText(selector: string, text: string): TestElement { - return new TestElement(element(by.cssContainingText(selector, text))); - } - - /** - * Performs a click on this element - */ - async click() { - return click(this.elementFinder); - } - - /** - * Checks that an element is present on the DOM of a page and visible - * - * @param waitTimeout How long to wait for the condition to be true - */ - async isVisible(waitTimeout?: number): Promise { - try { - await waitUntilElementIsVisible(this.elementFinder, waitTimeout); - return true; - } catch { - return false; - } - } - - /** - * Waits until the element is present on the DOM of a page and visible - * - * @param waitTimeout How long to wait for the condition to be true - */ - async waitVisible(waitTimeout?: number): Promise { - return waitUntilElementIsVisible(this.elementFinder, waitTimeout); - } - - /** - * Waits until the element is either invisible or not present on the DOM - * - * @param waitTimeout How long to wait for the condition to be true - */ - async waitNotVisible(waitTimeout?: number): Promise { - return waitUntilElementIsNotVisible(this.elementFinder, waitTimeout); - } - - /** - * Checks that an element is present on the DOM of a page - * - * @param waitTimeout How long to wait for the condition to be true - */ - async isPresent(waitTimeout?: number): Promise { - try { - await waitUntilElementIsPresent(this.elementFinder, waitTimeout); - return true; - } catch { - return false; - } - } - - /** - * Get the visible (i.e. not hidden by CSS) innerText of this element, including sub-elements, without any leading or trailing whitespace. - */ - async getText(): Promise { - return getText(this.elementFinder); - } - - /** - * Enter the text - * - * @param text the text to enter - */ - async typeText(text: string): Promise { - await clearSendKeys(this.elementFinder, text); - } -} diff --git a/projects/aca-testing-shared/src/utilities/user-actions.ts b/projects/aca-testing-shared/src/utilities/user-actions.ts deleted file mode 100644 index 2fc4f92695..0000000000 --- a/projects/aca-testing-shared/src/utilities/user-actions.ts +++ /dev/null @@ -1,169 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { AlfrescoApi, Comment, CommentsApi, NodesApi, TrashcanApi, SitesApi, SharedlinksApi } from '@alfresco/js-api'; -import { browser } from 'protractor'; - -export class UserActions { - protected readonly alfrescoApi: AlfrescoApi; - - readonly commentsApi: CommentsApi; - readonly nodesApi: NodesApi; - readonly trashcanApi: TrashcanApi; - readonly sitesApi: SitesApi; - readonly sharedLinksApi: SharedlinksApi; - - protected username: string; - protected password: string; - - constructor() { - this.alfrescoApi = new AlfrescoApi(); - this.alfrescoApi.setConfig(browser.params.config); - - this.commentsApi = new CommentsApi(this.alfrescoApi); - this.nodesApi = new NodesApi(this.alfrescoApi); - this.trashcanApi = new TrashcanApi(this.alfrescoApi); - this.sitesApi = new SitesApi(this.alfrescoApi); - this.sharedLinksApi = new SharedlinksApi(this.alfrescoApi); - } - - async login(username: string, password: string) { - this.username = username || this.username; - this.password = password || this.password; - - try { - return this.alfrescoApi.login(this.username, this.password); - } catch (error) { - this.handleError('User Actions - login failed : ', error); - } - } - - async createComment(nodeId: string, content: string): Promise { - try { - const comment = await this.commentsApi.createComment(nodeId, { content }); - return comment?.entry; - } catch (error) { - this.handleError('User Actions - createComment failed : ', error); - return null; - } - } - - /** - * Empties the trashcan. Uses multiple batches 1000 nodes each. - */ - async emptyTrashcan(): Promise { - try { - const nodes = await this.trashcanApi.listDeletedNodes({ - maxItems: 1000 - }); - - if (nodes?.list?.entries && nodes?.list?.entries?.length > 0) { - const ids = nodes.list.entries.map((entries) => entries.entry.id); - - for (const nodeId of ids) { - await this.trashcanApi.deleteDeletedNode(nodeId); - } - - await this.emptyTrashcan(); - } - } catch (error) { - this.handleError('User Actions - emptyTrashcan failed : ', error); - } - } - - async lockNodes(nodeIds: string[], lockType: string = 'ALLOW_OWNER_CHANGES') { - try { - for (const nodeId of nodeIds) { - await this.nodesApi.lockNode(nodeId, { type: lockType }); - } - } catch (error) { - this.handleError('User Actions - lockNodes failed : ', error); - } - } - - /** - * Unlock multiple nodes. - * @param nodeIds The list of node IDs to unlock. - */ - async unlockNodes(nodeIds: string[]): Promise { - try { - for (const nodeId of nodeIds) { - await this.nodesApi.unlockNode(nodeId); - } - } catch (error) { - this.handleError('User Actions - unlockNodes failed : ', error); - } - } - - /** - * Delete multiple sites/libraries. - * @param siteIds The list of the site/library IDs to delete. - * @param permanent Delete permanently, without moving to the trashcan? (default: true) - */ - async deleteSites(siteIds: string[], permanent: boolean = true) { - try { - if (siteIds && siteIds.length > 0) { - for (const siteId of siteIds) { - await this.sitesApi.deleteSite(siteId, { permanent }); - } - } - } catch (error) { - this.handleError('User Actions - deleteSites failed : ', error); - } - } - - /** - * Creates shared links for the given nodes. - * @param nodeIds The list of node IDs to share. - * @param expiresAt (optional) Expiration date. - */ - async shareNodes(nodeIds: string[], expiresAt?: Date): Promise { - try { - for (const nodeId of nodeIds) { - await this.sharedLinksApi.createSharedLink({ - nodeId, - expiresAt - }); - } - } catch (error) { - this.handleError('User Actions - shareNodes failed : ', error); - } - } - - protected handleError(message: string, response: any) { - console.error(`\n--- ${message} error :`); - console.error('\t>>> username: ', this.username); - console.error('\t>>> JSON: ', JSON.stringify(browser.params.config)); - if (response.status && response.response) { - try { - console.error('\t>>> Status: ', response.status); - console.error('\t>>> Text: ', response.response.text); - console.error('\t>>> Method: ', response.response.error.method); - console.error('\t>>> Path: ', response.response.error.path); - } catch { - console.error('\t>>> ', response); - } - } else console.error('\t>>> ', response); - } -} diff --git a/projects/aca-testing-shared/src/utilities/utils.ts b/projects/aca-testing-shared/src/utilities/utils.ts deleted file mode 100644 index 5ae8829507..0000000000 --- a/projects/aca-testing-shared/src/utilities/utils.ts +++ /dev/null @@ -1,184 +0,0 @@ -/*! - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { browser, protractor, ElementFinder, ExpectedConditions as EC, by, until, WebElement } from 'protractor'; -import { BROWSER_WAIT_TIMEOUT } from '../configs'; -import * as path from 'path'; -import * as fs from 'fs'; -import { waitUntilElementIsPresent, waitUntilElementIsVisible } from './browser-visibility'; - -const StreamZip = require('node-stream-zip'); -const crypto = require('crypto'); - -export async function typeText(element: ElementFinder, text: string): Promise { - await element.clear(); - await element.sendKeys(text); -} - -export async function clearTextWithBackspace(element: ElementFinder): Promise { - await element.clear(); - await element.sendKeys(' ', protractor.Key.CONTROL, 'a', protractor.Key.NULL, protractor.Key.BACK_SPACE); -} - -export async function waitElement(css: string, errorMessage?: string): Promise { - return browser.wait(until.elementLocated(by.css(css)), BROWSER_WAIT_TIMEOUT, errorMessage || `Timeout waiting for element: ${css}`); -} - -export async function waitForPresence(element: ElementFinder, errorMessage?: string): Promise { - await browser.wait(EC.presenceOf(element), BROWSER_WAIT_TIMEOUT, errorMessage || `Timeout waiting for element presence: ${element.locator()}`); -} - -export async function waitForStaleness(element: ElementFinder, errorMessage?: string): Promise { - await browser.wait(EC.stalenessOf(element), BROWSER_WAIT_TIMEOUT, errorMessage || `Timeout waiting element staleness: ${element.locator()}`); -} - -export const isPresentAndEnabled = async (element: ElementFinder): Promise => { - try { - await waitUntilElementIsPresent(element); - return element.isEnabled(); - } catch (error) { - return false; - } -}; - -export const isPresentAndDisplayed = async (element: ElementFinder): Promise => { - try { - await waitUntilElementIsVisible(element); - return true; - } catch (error) { - return false; - } -}; - -export class Utils { - static string257 = - 'assembly doctor offender limit clearance inspiration baker fraud active apples trait brainstorm concept breaks down presidential \ - reluctance summary communication patience books opponent banana economist head develop project swear unanimous read conservation'; - - static string513 = - 'great indirect brain tune other expectation fun silver drain tumble rhythm harmful wander picture distribute opera complication copyright \ - explosion snack ride pool machinery pair frog joint wrestle video referee drive window cage falsify happen tablet horror thank conception \ - extension decay dismiss platform respect ceremony applaud absorption presentation dominate race courtship soprano body \ - lighter track cinema tread tick climate lend summit singer radical flower visual negotiation promises cooperative live'; - - static random(): string { - return crypto.getRandomValues(new Uint32Array(1))[0].toString(36).substring(0, 5).toLowerCase(); - } - - static retryCall(fn: () => Promise, retry: number = 30, delay: number = 1500): Promise { - const pause = (duration: number) => new Promise((res) => setTimeout(res, duration)); - - const run = (retries: number): Promise => { - return fn().catch((err) => (retries > 1 ? pause(delay).then(() => run(retries - 1)) : Promise.reject(err))); - }; - - return run(retry); - } - - static async fileExistsOnOS(fileName: string, folderName: string = '', subFolderName: string = ''): Promise { - const config = await browser.getProcessedConfig(); - const filePath = path.join(config.params.downloadFolder, folderName, subFolderName, fileName); - - let tries = 15; - - return new Promise(function (resolve) { - const checkExist = setInterval(() => { - fs.access(filePath, function (error: any) { - tries--; - - if (error && tries === 0) { - clearInterval(checkExist); - resolve(false); - } - - if (!error) { - clearInterval(checkExist); - resolve(true); - } - }); - }, 500); - }); - } - - static async renameFile(oldName: string, newName: string): Promise { - const config = await browser.getProcessedConfig(); - const oldFilePath = path.join(config.params.downloadFolder, oldName); - const newFilePath = path.join(config.params.downloadFolder, newName); - - const fileExists = await this.fileExistsOnOS(oldName); - - if (fileExists) { - fs.rename(oldFilePath, newFilePath, function (err: any) { - if (err) { - console.error(`==== rename err : failed to rename file from ${oldName} to ${newName} : `, err); - } - }); - } - } - - static async unzip(filename: string, unzippedName: string = ''): Promise { - const config = await browser.getProcessedConfig(); - const filePath = path.join(config.params.downloadFolder, filename); - const output = path.join(config.params.downloadFolder, unzippedName ? unzippedName : ''); - - const zip = new StreamZip({ - file: filePath, - storeEntries: true - }); - - await zip.on('error', (err: any) => { - console.error(`=== unzip err : failed to unzip ${filename} - ${unzippedName} :`, err); - }); - - await zip.on('ready', async () => { - if (unzippedName) { - await fs.mkdirSync(output); - } - await zip.extract(null, output, async () => { - await zip.close(); - }); - }); - } - - static async pressEscape(): Promise { - await browser.actions().sendKeys(protractor.Key.ESCAPE).perform(); - } - - static async pressTab(): Promise { - await browser.actions().sendKeys(protractor.Key.TAB).perform(); - } - - static async pressCmd(): Promise { - await browser.actions().sendKeys(protractor.Key.COMMAND).perform(); - } - - static async releaseKeyPressed(): Promise { - await browser.actions().sendKeys(protractor.Key.NULL).perform(); - } - - static async uploadFileNewVersion(fileFromOS: string): Promise { - const el = browser.element(by.id('app-upload-file-version')); - await el.sendKeys(`${browser.params.e2eRootPath}/resources/test-files/${fileFromOS}`); - } -} diff --git a/projects/aca-testing-shared/tsconfig.lib.json b/projects/aca-testing-shared/tsconfig.lib.json deleted file mode 100644 index 3fd17214b0..0000000000 --- a/projects/aca-testing-shared/tsconfig.lib.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "../../out-tsc/aca-testing", - "target": "es2015", - "module": "es2015", - "moduleResolution": "node", - "declaration": true, - "sourceMap": true, - "inlineSources": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "importHelpers": true, - "types": [], - "lib": ["dom", "es2018"] - }, - "angularCompilerOptions": { - "skipTemplateCodegen": true, - "strictMetadataEmit": true, - "fullTemplateTypeCheck": true, - "strictInjectionParameters": true, - "enableResourceInlining": true - }, - "exclude": ["node_modules", "src/test.ts", "**/*.spec.ts"] -} diff --git a/protractor.conf.js b/protractor.conf.js deleted file mode 100755 index 1f4aa777dd..0000000000 --- a/protractor.conf.js +++ /dev/null @@ -1,225 +0,0 @@ -// Protractor configuration file, see link for more information -// https://github.com/angular/protractor/blob/master/lib/config.ts - -require('dotenv').config({path: process.env.ENV_FILE}); -const path = require('path'); -const {SpecReporter} = require('jasmine-spec-reporter'); -const retry = require('protractor-retry-angular-cli').retry; -const {saveScreenshots} = require('./e2e/protractor/e2e-config/utils/upload-output'); -const smartRunnerFactory = require('./e2e/protractor/smartrunner-factory'); -const argv = require('yargs').argv; - -const projectRoot = path.resolve(__dirname); -const downloadFolder = path.join(__dirname, 'e2e-downloads'); -const screenshotsFolder = path.resolve(__dirname, 'e2e-output'); -const e2eFolder = path.resolve(projectRoot, 'e2e/protractor'); -const E2E_HOST = process.env.E2E_HOST || 'http://localhost:4200'; -const BROWSER_RUN = !!process.env.BROWSER_RUN; -const width = 1366; -const height = 768; - -const SAVE_SCREENSHOT = process.env.SAVE_SCREENSHOT === 'true'; -const MAXINSTANCES = process.env.MAXINSTANCES || 1; -const E2E_LOG_LEVEL = process.env.E2E_LOG_LEVEL || 'ERROR'; -const E2E_TS_CONFIG_FOR_ADF = 'tsconfig.e2e.adf.json'; -const LOCAL_ADF_OPTION = '--with-local-adf'; - -const { BASE_URL } = process.env; - -const appConfig = { - hostEcm: BASE_URL || 'http://localhost:8080', - providers: 'ECM', - authType: 'BASIC' -}; - -exports.config = { - allScriptsTimeout: 150000, - - params: { - index_search: 25000, - config: appConfig, - downloadFolder: downloadFolder, - ADMIN_USERNAME: process.env.ADMIN_EMAIL || 'admin', - ADMIN_PASSWORD: process.env.ADMIN_PASSWORD || 'admin', - e2eRootPath: e2eFolder, - testConfig: { - appConfig: { - log: E2E_LOG_LEVEL - } - } - }, - - specs: [ - './e2e/protractor/suites/actions/**/**/*test.ts', - './e2e/protractor/suites/application/**/*test.ts', - './e2e/protractor/suites/authentication/**/*test.ts', - './e2e/protractor/suites/extensions/**/*test.ts', - './e2e/protractor/suites/info-drawer/**/*test.ts', - './e2e/protractor/suites/list-views/**/*test.ts', - './e2e/protractor/suites/pagination/**/*test.ts', - './e2e/protractor/suites/search/**/*test.ts', - './e2e/protractor/suites/viewer/**/*test.ts' - ], - - suites: { - copyMoveActions: './e2e/protractor/suites/actions/copy-move/**/**/*test.ts', - createActions: './e2e/protractor/suites/actions/create/**/**/*test.ts', - deleteActions: './e2e/protractor/suites/actions/delete/**/**/*test.ts', - editActions: './e2e/protractor/suites/actions/edit/**/**/*test.ts', - favoriteActions: './e2e/protractor/suites/actions/favorite/**/**/*test.ts', - libraryActions: './e2e/protractor/suites/actions/library/**/**/*test.ts', - shareActions: './e2e/protractor/suites/actions/share/**/**/*test.ts', - uploadDownloadActions: './e2e/protractor/suites/actions/upload-download/**/**/*test.ts', - - application: './e2e/protractor/suites/application/**/*test.ts', - authentication: './e2e/protractor/suites/authentication/**/*test.ts', - extensions: './e2e/protractor/suites/extensions/**/*test.ts', - infoDrawer: './e2e/protractor/suites/info-drawer/**/*test.ts', - listViews: './e2e/protractor/suites/list-views/**/*test.ts', - pagination: './e2e/protractor/suites/pagination/**/*test.ts', - search: './e2e/protractor/suites/search/**/*test.ts', - viewer: './e2e/protractor/suites/viewer/**/*test.ts' - }, - - SELENIUM_PROMISE_MANAGER: false, - - capabilities: { - loggingPrefs: { - browser: 'ALL' // "OFF", "SEVERE", "WARNING", "INFO", "CONFIG", "FINE", "FINER", "FINEST", "ALL". - }, - - browserName: 'chrome', - - maxInstances: MAXINSTANCES, - - shardTestFiles: MAXINSTANCES > 1, - - chromeOptions: { - prefs: { - credentials_enable_service: false, - download: { - prompt_for_download: false, - directory_upgrade: true, - default_directory: downloadFolder - }, - browser: { - setDownloadBehavior: { - behavior: 'allow', - downloadPath: downloadFolder - } - } - }, - args: [ - `--window-size=${width},${height}`, - '--disable-gpu', - '--no-sandbox', - '--disable-web-security', - '--disable-browser-side-navigation', - '--allow-running-insecure-content', - ...(BROWSER_RUN === true ? [] : ['--headless']) - ] - } - }, - - directConnect: true, - - baseUrl: E2E_HOST, - - getPageTimeout: 150000, - - framework: 'jasmine', - jasmineNodeOpts: { - showColors: true, - defaultTimeoutInterval: 200000, - includeStackTrace: true, - ...(process.env.CI ? smartRunnerFactory.applyExclusionFilter() : {}) - }, - - plugins: [ - { - package: 'protractor-screenshoter-plugin', - screenshotPath: screenshotsFolder, - screenshotOnExpect: 'failure', - screenshotOnSpec: 'none', - withLogs: true, - writeReportFreq: 'end', - imageToAscii: 'none', - htmlOnExpect: 'none', - htmlOnSpec: 'none', - clearFoldersBeforeTest: true - } - ], - - onCleanUp(results) { - if (process.env.CI) { - retry.onCleanUp(results); - } - }, - - onPrepare() { - if (process.env.CI) { - retry.onPrepare(); - smartRunnerFactory.getInstance().onPrepare(); - } - - const withLocalAdf = process.argv.indexOf(LOCAL_ADF_OPTION) !== -1; - const tsConfigPath = path.resolve(e2eFolder, withLocalAdf ? E2E_TS_CONFIG_FOR_ADF : 'tsconfig.e2e.json'); - const tsConfig = require(tsConfigPath); - - require('ts-node').register({ - project: tsConfigPath, - compilerOptions: { - paths: tsConfig.compilerOptions.paths - } - }); - - require('tsconfig-paths').register({ - project: tsConfigPath, - baseUrl: e2eFolder, - paths: tsConfig.compilerOptions.paths - }); - - // eslint-disable-next-line no-undef - browser.manage().window().setSize(width, height); - - // eslint-disable-next-line no-undef - jasmine.getEnv().addReporter( - new SpecReporter({ - spec: { - displayStacktrace: 'raw', - displayDuration: true - } - }) - ); - - // eslint-disable-next-line no-undef - browser.driver.sendChromiumCommand('Page.setDownloadBehavior', { - behavior: 'allow', - downloadPath: downloadFolder - }); - }, - - afterLaunch: async function (statusCode) { - if (SAVE_SCREENSHOT && statusCode !== 0) { - console.log(`Status code is ${statusCode}, trying to save screenshots.`); - - let retryCount = 1; - if (argv.retry) { - retryCount = ++argv.retry; - } - - try { - await saveScreenshots(retryCount, (process.env.FOLDER || '')); - console.log('Screenshots saved successfully.'); - } catch (e) { - console.log('Error happened while trying to upload screenshots and test reports: ', e); - } - } else { - console.log(`Status code is ${statusCode}, no need to save screenshots.`); - } - - if (process.env.CI) { - return retry.afterLaunch(process.env.RETRY_COUNT || 4, statusCode); - } - } -}; diff --git a/scripts/webdriver-update-newest/README.md b/scripts/webdriver-update-newest/README.md deleted file mode 100644 index 80a38ef3d4..0000000000 --- a/scripts/webdriver-update-newest/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# Run protractor with newest webdriver locally - -## Instruction -To download newest driver simply run script from its directory -`update-to-newest-webdriver.sh` - -Command accepts one parameter to define what OS you are using. By default its set to `mac-x64` -Possible inputs `linux64, mac-arm64, mac-x64, win32, win64` - -Example `./update-to-newest-webdriver.sh win64` - will set driver for windows - -## How it works -1. The script removes your existing driver files from webdriver node_modules -2. Generates two new files (chrome_xml.js and update.js) that have updated methods needed to get the new driver -3. Replaces browser type depending on parameter -4. Copies and replaces the files to the webdriver node_modules -5. Executes command to to update-webdriver using updated code - -## Troubleshooting -If the script fails for any reason. You can do some of these actions manually: -1. Find the two files (chrome_xml.js and update.js) in node_modules/webdriver-manager -2. Replace its contents with (chrome_xml_schema.js and update_schema.js) keep the original names. -3. Change version for specific OS in both files - chrome_xml.js -> ['platform'] == 'mac-x64' e.g. ['platform'] == 'win64' Line 70 - update.js -> 'chromedriver-mac-x64' e.g 'chromedriver-win64' Line 240 -4. Run standard command to update webdriver `./node_modules/webdriver-manager/bin/webdriver-manager update --gecko=false` - - - -## Reason -Latest ChromeDriver Binaries https://googlechromelabs.github.io/chrome-for-testing/ - -Starting with M115 the latest Chrome + ChromeDriver releases per release channel (Stable, Beta, Dev, Canary) are available at the Chrome for Testing availability dashboard. For automated version downloading one can use the convenient JSON endpoints. -The older releases can be found at the Downloads page. - - -Note: Protractor is a depricated tool and this probably won't be fixed. \ No newline at end of file diff --git a/scripts/webdriver-update-newest/chrome_xml_schema.js b/scripts/webdriver-update-newest/chrome_xml_schema.js deleted file mode 100644 index 5f33d056b3..0000000000 --- a/scripts/webdriver-update-newest/chrome_xml_schema.js +++ /dev/null @@ -1,181 +0,0 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -const semver = require('semver'); -const config_1 = require('../config'); -const http_utils_1 = require('../http_utils'); -const config_source_1 = require('./config_source'); -class ChromeXml extends config_source_1.XmlConfigSource { - constructor() { - super('chrome', config_1.Config.cdnUrls()['chrome']); - this.maxVersion = config_1.Config.binaryVersions().maxChrome; - } - getUrl(version) { - if (version === 'latest') { - return this.getLatestChromeDriverVersion(); - } else { - return this.getSpecificChromeDriverVersion(version); - } - } - /** - * Get a list of chrome drivers paths available for the configuration OS type and architecture. - */ - getVersionList() { - return this.getXml().then((xml) => { - let versionPaths = []; - let osType = this.getOsTypeName(); - for (let content of xml.ListBucketResult.Contents) { - let contentKey = content.Key[0]; - if ( - // Filter for 32-bit devices, make sure x64 is not an option - (this.osarch.includes('64') || !contentKey.includes('64')) && - // Filter for x86 macs, make sure m1 is not an option - ((this.ostype === 'Darwin' && this.osarch === 'arm64') || !contentKey.includes('m1')) - ) { - // Filter for only the osType - if (contentKey.includes(osType)) { - versionPaths.push(contentKey); - } - } - } - return versionPaths; - }); - } - /** - * Helper method, gets the ostype and gets the name used by the XML - */ - getOsTypeName() { - // Get the os type name. - if (this.ostype === 'Darwin') { - return 'mac-x64'; - } else if (this.ostype === 'Windows_NT') { - return 'win64'; - } else { - return 'linux64'; - } - } - /** - * Gets the latest item from the XML. - */ - getLatestChromeDriverVersion() { - const path = require('path'); - const fs = require('fs'); - - const lastKnownGoodVersionsWithDownloads_Url = - 'https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json'; - return http_utils_1.requestBody(lastKnownGoodVersionsWithDownloads_Url).then((body) => { - const latestVersion_Body = JSON.parse(body)['channels']['Stable']; - - const latestVersion = latestVersion_Body['version']; - const latestVersion_Url = latestVersion_Body['downloads']['chromedriver'].find((obj) => obj['platform'] == 'mac-x64')['url']; - - const latestMajorVersion = latestVersion.split('.')[0]; - - const localVersion_FileName = - fs - .readdirSync(path.resolve(__dirname, '..', '..', '..', 'selenium')) - .find((f) => f.startsWith(`chromedriver_${latestMajorVersion}`)) || ''; - - const localVersion = localVersion_FileName.slice(13, -4); - const localVersion_Url = latestVersion_Url.replace(latestVersion, localVersion); - - const localMajorVersion = localVersion.split('.')[0]; - - if (latestMajorVersion == localMajorVersion) { - return Promise.resolve({ - url: localVersion_Url, - version: localVersion - }); - } else { - return Promise.resolve({ - url: latestVersion_Url, - version: latestVersion - }); - } - }); - } - /** - * Gets a specific item from the XML. - */ - getSpecificChromeDriverVersion(versionRequired) { - const path = require('path'); - const fs = require('fs'); - - let baseTagVersion = versionRequired.split('.'); - baseTagVersion.splice(-1); - baseTagVersion = baseTagVersion.join('.'); - - const lastKnownGoodVersionsWithDownloads_Url = - 'https://googlechromelabs.github.io/chrome-for-testing/latest-patch-versions-per-build-with-downloads.json'; - return http_utils_1.requestBody(lastKnownGoodVersionsWithDownloads_Url).then((body) => { - const version_Body = JSON.parse(body)['builds'][baseTagVersion]; - - const opSys = this.getOsTypeName(); - - const currentVersion = version_Body['version']; - const currentVersion_Url = version_Body['downloads']['chromedriver'].find((obj) => obj['platform'] == opSys)['url']; - - const latestMajorVersion = currentVersion.split('.')[0]; - - const localVersion_FileName = - fs - .readdirSync(path.resolve(__dirname, '..', '..', '..', 'selenium')) - .find((f) => f.startsWith(`chromedriver_${latestMajorVersion}`)) || ''; - - const localVersion = localVersion_FileName.slice(13, -4); - const localVersion_Url = currentVersion_Url.replace(currentVersion, localVersion); - - const localMajorVersion = localVersion.split('.')[0]; - - if (latestMajorVersion == localMajorVersion) { - return Promise.resolve({ - url: localVersion_Url, - version: localVersion - }); - } else { - return Promise.resolve({ - url: currentVersion_Url, - version: currentVersion - }); - } - }); - } -} -exports.ChromeXml = ChromeXml; -/** - * Chromedriver is the only binary that does not conform to semantic versioning - * and either has too little number of digits or too many. To get this to be in - * semver, we will either add a '.0' at the end or chop off the last set of - * digits. This is so we can compare to find the latest and greatest. - * - * Example: - * 2.46 -> 2.46.0 - * 75.0.3770.8 -> 75.0.3770 - * - * @param version - */ -function getValidSemver(version) { - let lookUpVersion = ''; - // This supports downloading 2.46 - try { - const oldRegex = /(\d+.\d+)/g; - const exec = oldRegex.exec(version); - if (exec) { - lookUpVersion = exec[1] + '.0'; - } - } catch (_) { - // no-op: is this is not valid, do not throw here. - } - // This supports downloading 74.0.3729.6 - try { - const newRegex = /(\d+.\d+.\d+).\d+/g; - const exec = newRegex.exec(version); - if (exec) { - lookUpVersion = exec[1]; - } - } catch (_) { - // no-op: if this does not work, use the other regex pattern. - } - return lookUpVersion; -} -exports.getValidSemver = getValidSemver; -//# sourceMappingURL=chrome_xml.js.map diff --git a/scripts/webdriver-update-newest/update-to-newest-webdriver.sh b/scripts/webdriver-update-newest/update-to-newest-webdriver.sh deleted file mode 100755 index 979b3029c2..0000000000 --- a/scripts/webdriver-update-newest/update-to-newest-webdriver.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env bash -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -echo "Getting currently installed Chrome Version" - -if [ "$CI" = "true" ]; then - chromeVersion=$(google-chrome --version ) -else - chromeVersion=$(/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version ) -fi - -chromeVersion=${chromeVersion:14:20} - -echo "Intalling webdriver for version: $chromeVersion" - -function show_error() { - echo -e "\e[31m===============================================================\e[0m" - echo -e "\e[31mFAILED TO UPDATE WEBDRIVER-MANAGER, PLEASE DO IT MANUALLY!\e[0m" - echo -e "\e[31mRun the following command (sometimes needs more than one kick):\e[0m" - echo -e "" - echo -e "\e[31mnpx webdriver-manager update --gecko=false\e[0m" - echo -e "" - echo -e "\e[31m===============================================================\e[0m" -} - -ROOTDIR="$DIR/.." - -if [ "$(uname)" == "Darwin" ]; then - BROWSER_TYPE="mac-x64" -elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then - BROWSER_TYPE="linux64" -elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then - BROWSER_TYPE="win32" -elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW64_NT" ]; then - BROWSER_TYPE="win64" -fi - -echo "BROWSER => $BROWSER_TYPE" - - -PATH_TO_COMMANDS=./node_modules/webdriver-manager/built/lib/cmds -PATH_TO_BINARIES=./node_modules/webdriver-manager/built/lib/binaries -PATH_TO_SELENIUM=./node_modules/webdriver-manager/selenium - -# Remove existing drivers -rm -rf $PATH_TO_SELENIUM/selenium-server-* -rm -rf $PATH_TO_SELENIUM/chromedriver-* -rm -f $PATH_TO_SELENIUM/chromedriver_* - -# Replace browser type in file and create new file -echo 'Replacing new webdriver files' -sed "s/mac-x64/$BROWSER_TYPE/" $DIR/chrome_xml_schema.js > $DIR/chrome_xml.js && sed "s/mac-x64/$BROWSER_TYPE/" $DIR/update_schema.js > $DIR/update.js; - -if [ "$?" -ne 0 ]; then - show_error - exit 0 -fi - -echo "============== Trying to update the files ==============" -sleep 2 - -# Replace webdriver files -echo "cp -f $DIR/update.js $PATH_TO_COMMANDS/update.js" -cp -f $DIR/update.js $PATH_TO_COMMANDS/update.js -cp -f $DIR/chrome_xml.js $PATH_TO_BINARIES/chrome_xml.js - -rm -f $DIR/update.js -rm -f $DIR/chrome_xml.js - -node ./node_modules/webdriver-manager/bin/webdriver-manager update --gecko=false --versions.chrome=$chromeVersion - - diff --git a/scripts/webdriver-update-newest/update_schema.js b/scripts/webdriver-update-newest/update_schema.js deleted file mode 100644 index 942097d104..0000000000 --- a/scripts/webdriver-update-newest/update_schema.js +++ /dev/null @@ -1,304 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const AdmZip = require("adm-zip"); -const child_process = require("child_process"); -const fs = require("fs"); -const minimist = require("minimist"); -const path = require("path"); -const q = require("q"); -const rimraf = require("rimraf"); -const binaries_1 = require("../binaries"); -const cli_1 = require("../cli"); -const config_1 = require("../config"); -const files_1 = require("../files"); -const http_utils_1 = require("../http_utils"); -const utils_1 = require("../utils"); -const Opt = require("./"); -const initialize_1 = require("./initialize"); -const opts_1 = require("./opts"); -config_1.Config.runCommand = 'update'; -let logger = new cli_1.Logger('update'); -let prog = new cli_1.Program() - .command('update', 'install or update selected binaries') - .action(update) - .addOption(opts_1.Opts[Opt.OUT_DIR]) - .addOption(opts_1.Opts[Opt.VERBOSE]) - .addOption(opts_1.Opts[Opt.IGNORE_SSL]) - .addOption(opts_1.Opts[Opt.PROXY]) - .addOption(opts_1.Opts[Opt.ALTERNATE_CDN]) - .addOption(opts_1.Opts[Opt.STANDALONE]) - .addOption(opts_1.Opts[Opt.CHROME]) - .addOption(opts_1.Opts[Opt.GECKO]) - .addOption(opts_1.Opts[Opt.ANDROID]) - .addOption(opts_1.Opts[Opt.ANDROID_API_LEVELS]) - .addOption(opts_1.Opts[Opt.ANDROID_ARCHITECTURES]) - .addOption(opts_1.Opts[Opt.ANDROID_PLATFORMS]) - .addOption(opts_1.Opts[Opt.ANDROID_ACCEPT_LICENSES]); -if (config_1.Config.osType() === 'Darwin') { - prog.addOption(opts_1.Opts[Opt.IOS]); -} -if (config_1.Config.osType() === 'Windows_NT') { - prog.addOption(opts_1.Opts[Opt.IE]).addOption(opts_1.Opts[Opt.IE32]).addOption(opts_1.Opts[Opt.IE64]); -} -prog.addOption(opts_1.Opts[Opt.VERSIONS_STANDALONE]) - .addOption(opts_1.Opts[Opt.VERSIONS_CHROME]) - .addOption(opts_1.Opts[Opt.VERSIONS_APPIUM]) - .addOption(opts_1.Opts[Opt.VERSIONS_ANDROID]) - .addOption(opts_1.Opts[Opt.VERSIONS_GECKO]); -if (config_1.Config.osType() === 'Windows_NT') { - prog.addOption(opts_1.Opts[Opt.VERSIONS_IE]); -} -exports.program = prog; -// stand alone runner -let argv = minimist(process.argv.slice(2), prog.getMinimistOptions()); -if (argv._[0] === 'update-run') { - prog.run(JSON.parse(JSON.stringify(argv))); -} -else if (argv._[0] === 'update-help') { - prog.printHelp(); -} -let browserFile; -/** - * Parses the options and downloads binaries if they do not exist. - * @param options - */ -function update(options) { - let promises = []; - let standalone = options[Opt.STANDALONE].getBoolean(); - let chrome = options[Opt.CHROME].getBoolean(); - let gecko = options[Opt.GECKO].getBoolean(); - let ie32 = false; - let ie64 = false; - if (options[Opt.IE]) { - ie32 = ie32 || options[Opt.IE].getBoolean(); - } - if (options[Opt.IE32]) { - ie32 = ie32 || options[Opt.IE32].getBoolean(); - } - if (options[Opt.IE64]) { - ie64 = options[Opt.IE64].getBoolean(); - } - let android = options[Opt.ANDROID].getBoolean(); - let ios = false; - if (options[Opt.IOS]) { - ios = options[Opt.IOS].getBoolean(); - } - let outputDir = options[Opt.OUT_DIR].getString(); - try { - browserFile = - JSON.parse(fs.readFileSync(path.resolve(outputDir, 'update-config.json')).toString()); - } - catch (err) { - browserFile = {}; - } - let android_api_levels = options[Opt.ANDROID_API_LEVELS].getString().split(','); - let android_architectures = options[Opt.ANDROID_ARCHITECTURES].getString().split(','); - let android_platforms = options[Opt.ANDROID_PLATFORMS].getString().split(','); - let android_accept_licenses = options[Opt.ANDROID_ACCEPT_LICENSES].getBoolean(); - if (options[Opt.OUT_DIR].getString()) { - if (path.isAbsolute(options[Opt.OUT_DIR].getString())) { - outputDir = options[Opt.OUT_DIR].getString(); - } - else { - outputDir = path.resolve(config_1.Config.getBaseDir(), options[Opt.OUT_DIR].getString()); - } - files_1.FileManager.makeOutputDirectory(outputDir); - } - let ignoreSSL = options[Opt.IGNORE_SSL].getBoolean(); - let proxy = options[Opt.PROXY].getString(); - http_utils_1.HttpUtils.assignOptions({ ignoreSSL, proxy }); - let verbose = options[Opt.VERBOSE].getBoolean(); - // setup versions for binaries - let binaries = files_1.FileManager.setupBinaries(options[Opt.ALTERNATE_CDN].getString()); - binaries[binaries_1.Standalone.id].versionCustom = options[Opt.VERSIONS_STANDALONE].getString(); - binaries[binaries_1.ChromeDriver.id].versionCustom = options[Opt.VERSIONS_CHROME].getString(); - if (options[Opt.VERSIONS_IE]) { - binaries[binaries_1.IEDriver.id].versionCustom = options[Opt.VERSIONS_IE].getString(); - } - if (options[Opt.VERSIONS_GECKO]) { - binaries[binaries_1.GeckoDriver.id].versionCustom = options[Opt.VERSIONS_GECKO].getString(); - } - binaries[binaries_1.AndroidSDK.id].versionCustom = options[Opt.VERSIONS_ANDROID].getString(); - binaries[binaries_1.Appium.id].versionCustom = options[Opt.VERSIONS_APPIUM].getString(); - // if the file has not been completely downloaded, download it - // else if the file has already been downloaded, unzip the file, rename it, and give it - // permissions - if (standalone) { - let binary = binaries[binaries_1.Standalone.id]; - promises.push(files_1.FileManager.downloadFile(binary, outputDir) - .then((downloaded) => { - if (!downloaded) { - logger.info(binary.name + ': file exists ' + - path.resolve(outputDir, binary.filename())); - logger.info(binary.name + ': ' + binary.filename() + ' up to date'); - } - }) - .then(() => { - updateBrowserFile(binary, outputDir); - })); - } - if (chrome) { - let binary = binaries[binaries_1.ChromeDriver.id]; - promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL).then(() => { - return Promise.resolve(updateBrowserFile(binary, outputDir)); - })); - } - if (gecko) { - let binary = binaries[binaries_1.GeckoDriver.id]; - promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL).then(() => { - return Promise.resolve(updateBrowserFile(binary, outputDir)); - })); - } - if (ie64) { - let binary = binaries[binaries_1.IEDriver.id]; - binary.osarch = config_1.Config.osArch(); // Win32 or x64 - promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL).then(() => { - return Promise.resolve(updateBrowserFile(binary, outputDir)); - })); - } - if (ie32) { - let binary = binaries[binaries_1.IEDriver.id]; - binary.osarch = 'Win32'; - promises.push(updateBinary(binary, outputDir, proxy, ignoreSSL).then(() => { - return Promise.resolve(updateBrowserFile(binary, outputDir)); - })); - } - if (android) { - let binary = binaries[binaries_1.AndroidSDK.id]; - let sdk_path = path.resolve(outputDir, binary.executableFilename()); - let oldAVDList; - updateBrowserFile(binary, outputDir); - promises.push(q.nfcall(fs.readFile, path.resolve(sdk_path, 'available_avds.json')) - .then((oldAVDs) => { - oldAVDList = oldAVDs; - }, () => { - oldAVDList = '[]'; - }) - .then(() => { - return updateBinary(binary, outputDir, proxy, ignoreSSL); - }) - .then(() => { - initialize_1.android(path.resolve(outputDir, binary.executableFilename()), android_api_levels, android_architectures, android_platforms, android_accept_licenses, binaries[binaries_1.AndroidSDK.id].versionCustom, JSON.parse(oldAVDList), logger, verbose); - })); - } - if (ios) { - initialize_1.iOS(logger); - } - if (android || ios) { - installAppium(binaries[binaries_1.Appium.id], outputDir); - updateBrowserFile(binaries[binaries_1.Appium.id], outputDir); - } - return Promise.all(promises).then(() => { - writeBrowserFile(outputDir); - }); -} -function updateBinary(binary, outputDir, proxy, ignoreSSL) { - return files_1.FileManager - .downloadFile(binary, outputDir, (binary, outputDir, fileName) => { - unzip(binary, outputDir, fileName); - }) - .then(downloaded => { - if (!downloaded) { - // The file did not have to download, we should unzip it. - logger.info(binary.name + ': file exists ' + path.resolve(outputDir, binary.filename())); - let fileName = binary.filename(); - unzip(binary, outputDir, fileName); - logger.info(binary.name + ': ' + binary.executableFilename() + ' up to date'); - } - }); -} -function unzip(binary, outputDir, fileName) { - // remove the previously saved file and unzip it - let osType = config_1.Config.osType(); - let mv = path.resolve(outputDir, binary.executableFilename()); - try { - fs.unlinkSync(mv); - } - catch (err) { - try { - rimraf.sync(mv); - } - catch (err2) { - } - } - // unzip the file - logger.info(binary.name + ': unzipping ' + fileName); - if (fileName.slice(-4) == '.zip') { - try { - let zip = new AdmZip(path.resolve(outputDir, fileName)); - zip.extractAllTo(outputDir, true); - } - catch (e) { - throw new Error(`Invalid filename: ${path.resolve(outputDir, fileName)}`); - } - } - else { - // We will only ever get .tar files on linux - child_process.spawnSync('tar', ['zxvf', path.resolve(outputDir, fileName), '-C', outputDir]); - } - // rename - if (fileName.indexOf('chromedriver_') != -1) { - fs.renameSync(path.resolve(outputDir, 'chromedriver-mac-x64', binary.zipContentName()), mv) - } else { - fs.renameSync(path.resolve(outputDir, binary.zipContentName()), mv); - } - // set permissions - if (osType !== 'Windows_NT') { - logger.info(binary.name + ': setting permissions to 0755 for ' + mv); - if (binary.id() !== binaries_1.AndroidSDK.id) { - fs.chmodSync(mv, '0755'); - } - else { - fs.chmodSync(path.resolve(mv, 'tools', 'android'), '0755'); - fs.chmodSync(path.resolve(mv, 'tools', 'emulator'), '0755'); - // TODO(sjelin): get 64 bit versions working - } - } -} -function installAppium(binary, outputDir) { - logger.info('appium: installing appium'); - let folder = path.resolve(outputDir, binary.filename()); - try { - rimraf.sync(folder); - } - catch (err) { - } - fs.mkdirSync(folder); - fs.writeFileSync(path.resolve(folder, 'package.json'), JSON.stringify({ scripts: { appium: 'appium' } })); - utils_1.spawn('npm', ['install', 'appium@' + binary.version()], null, { cwd: folder }); -} -function updateBrowserFile(binary, outputDir) { - let currentDownload = path.resolve(outputDir, binary.executableFilename()); - // if browserFile[id] exists, we should update it - if (browserFile[binary.id()]) { - let binaryPath = browserFile[binary.id()]; - if (binaryPath.last === currentDownload) { - return; - } - else { - binaryPath.last = currentDownload; - for (let bin of binaryPath.all) { - if (bin === currentDownload) { - return; - } - } - binaryPath.all.push(currentDownload); - } - } - else { - // The browserFile[id] does not exist / has not been downloaded previously. - // We should create the entry. - let binaryPath = { last: currentDownload, all: [currentDownload] }; - browserFile[binary.id()] = binaryPath; - } -} -function writeBrowserFile(outputDir) { - let filePath = path.resolve(outputDir, 'update-config.json'); - fs.writeFileSync(filePath, JSON.stringify(browserFile)); -} -// for testing -function clearBrowserFile() { - browserFile = {}; -} -exports.clearBrowserFile = clearBrowserFile; -//# sourceMappingURL=update.js.map \ No newline at end of file