From f22a195876ac88e991f08baa22fbd752c3be4720 Mon Sep 17 00:00:00 2001 From: Martin Hradil Date: Tue, 31 Dec 2024 04:00:08 +0100 Subject: [PATCH] Tests (#147) * workflows/cypress: enable tests * cypress/e2e: remove tests * Add minimal smoke test * lang fixup * reorder to wait on Connection abort --- .github/workflows/cypress.yml | 140 ++++++++++ config/start.config.js | 1 + cypress.config.js | 18 +- cypress.env.json | 4 +- .../approval-multiple-repos-list.js | 155 ----------- .../approval-modal/approval-multiple-repos.js | 159 ------------ .../e2e/approval/approval-dashboard-list.js | 152 ----------- cypress/e2e/approval/approval-process.js | 74 ------ cypress/e2e/approval/collection-approval.js | 56 ---- cypress/e2e/approval/signing.js | 39 --- cypress/e2e/collections/collection-detail.js | 157 ------------ cypress/e2e/collections/collection-upload.js | 122 --------- cypress/e2e/collections/collection.js | 128 ---------- cypress/e2e/collections/collections-list.js | 145 ----------- cypress/e2e/namespaces/docs-menu.js | 23 -- .../namespaces/execution-environments-edit.js | 85 ------- .../e2e/namespaces/execution-environments.js | 39 --- cypress/e2e/namespaces/group-list.js | 62 ----- cypress/e2e/namespaces/group-management.js | 131 ---------- cypress/e2e/namespaces/group-roles.js | 157 ------------ cypress/e2e/namespaces/l10n.js | 61 ----- cypress/e2e/namespaces/login.js | 48 ---- cypress/e2e/namespaces/menu.js | 54 ---- cypress/e2e/namespaces/namespace-delete.js | 51 ---- cypress/e2e/namespaces/namespace-detail.js | 64 ----- cypress/e2e/namespaces/namespace-edit.js | 144 ----------- cypress/e2e/namespaces/namespace-form.js | 86 ------- cypress/e2e/namespaces/namespace-list.js | 16 -- cypress/e2e/namespaces/profile.js | 141 ---------- cypress/e2e/namespaces/rbac-access.js | 168 ------------ cypress/e2e/namespaces/rbac-create.js | 86 ------- cypress/e2e/namespaces/rbac-edit.js | 72 ------ cypress/e2e/namespaces/rbac-list.js | 19 -- cypress/e2e/namespaces/rbac.js | 240 ------------------ cypress/e2e/namespaces/task-list.js | 33 --- .../e2e/namespaces/task-management-detail.js | 44 ---- cypress/e2e/namespaces/task-status.js | 54 ---- cypress/e2e/namespaces/user-dashboard.js | 14 - cypress/e2e/namespaces/user-detail.js | 66 ----- cypress/e2e/namespaces/user-filter.js | 111 -------- cypress/e2e/namespaces/user-list.js | 77 ------ cypress/e2e/repo/container-signing.js | 86 ------- cypress/e2e/repo/imports-filter-search.js | 119 --------- cypress/e2e/repo/imports-filter.js | 84 ------ cypress/e2e/repo/remote-registry.js | 128 ---------- cypress/e2e/repo/repository-list.js | 164 ------------ cypress/e2e/repo/repository.js | 182 ------------- cypress/e2e/screenshots/screenshots.js | 42 --- cypress/e2e/smoke.js | 107 ++++++++ cypress/plugins/console-logger.js | 58 ----- cypress/support/commands.js | 234 ----------------- cypress/support/e2e.js | 31 ++- cypress/support/login.js | 41 --- package-lock.json | 91 ------- package.json | 3 - src/components/language-switcher.tsx | 4 +- 56 files changed, 284 insertions(+), 4586 deletions(-) create mode 100644 .github/workflows/cypress.yml delete mode 100644 cypress/e2e/approval-modal/approval-multiple-repos-list.js delete mode 100644 cypress/e2e/approval-modal/approval-multiple-repos.js delete mode 100644 cypress/e2e/approval/approval-dashboard-list.js delete mode 100644 cypress/e2e/approval/approval-process.js delete mode 100644 cypress/e2e/approval/collection-approval.js delete mode 100644 cypress/e2e/approval/signing.js delete mode 100644 cypress/e2e/collections/collection-detail.js delete mode 100644 cypress/e2e/collections/collection-upload.js delete mode 100644 cypress/e2e/collections/collection.js delete mode 100644 cypress/e2e/collections/collections-list.js delete mode 100644 cypress/e2e/namespaces/docs-menu.js delete mode 100644 cypress/e2e/namespaces/execution-environments-edit.js delete mode 100644 cypress/e2e/namespaces/execution-environments.js delete mode 100644 cypress/e2e/namespaces/group-list.js delete mode 100644 cypress/e2e/namespaces/group-management.js delete mode 100644 cypress/e2e/namespaces/group-roles.js delete mode 100644 cypress/e2e/namespaces/l10n.js delete mode 100644 cypress/e2e/namespaces/login.js delete mode 100644 cypress/e2e/namespaces/menu.js delete mode 100644 cypress/e2e/namespaces/namespace-delete.js delete mode 100644 cypress/e2e/namespaces/namespace-detail.js delete mode 100644 cypress/e2e/namespaces/namespace-edit.js delete mode 100644 cypress/e2e/namespaces/namespace-form.js delete mode 100644 cypress/e2e/namespaces/namespace-list.js delete mode 100644 cypress/e2e/namespaces/profile.js delete mode 100644 cypress/e2e/namespaces/rbac-access.js delete mode 100644 cypress/e2e/namespaces/rbac-create.js delete mode 100644 cypress/e2e/namespaces/rbac-edit.js delete mode 100644 cypress/e2e/namespaces/rbac-list.js delete mode 100644 cypress/e2e/namespaces/rbac.js delete mode 100644 cypress/e2e/namespaces/task-list.js delete mode 100644 cypress/e2e/namespaces/task-management-detail.js delete mode 100644 cypress/e2e/namespaces/task-status.js delete mode 100644 cypress/e2e/namespaces/user-dashboard.js delete mode 100644 cypress/e2e/namespaces/user-detail.js delete mode 100644 cypress/e2e/namespaces/user-filter.js delete mode 100644 cypress/e2e/namespaces/user-list.js delete mode 100644 cypress/e2e/repo/container-signing.js delete mode 100644 cypress/e2e/repo/imports-filter-search.js delete mode 100644 cypress/e2e/repo/imports-filter.js delete mode 100644 cypress/e2e/repo/remote-registry.js delete mode 100644 cypress/e2e/repo/repository-list.js delete mode 100644 cypress/e2e/repo/repository.js delete mode 100644 cypress/e2e/screenshots/screenshots.js create mode 100644 cypress/e2e/smoke.js delete mode 100644 cypress/plugins/console-logger.js delete mode 100644 cypress/support/commands.js delete mode 100644 cypress/support/login.js diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml new file mode 100644 index 00000000..5bea79fb --- /dev/null +++ b/.github/workflows/cypress.yml @@ -0,0 +1,140 @@ +name: Cypress + +on: + # allow running manually + workflow_dispatch: + pull_request: + branches: ['main'] + # weekly on main + schedule: + - cron: '14 4 * * 6' + +concurrency: + group: cypress-${{ github.ref }} + cancel-in-progress: true + +jobs: + cypress: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + steps: + - name: 'Checkout pulp-ui (${{ github.ref }})' + uses: actions/checkout@v4 + + - name: 'backend setup' + run: | + mkdir -p settings/certs pulp_storage pgsql containers + echo "CONTENT_ORIGIN='http://$(hostname):8080'" >> settings/settings.py + echo "ANSIBLE_API_HOSTNAME='http://$(hostname):8080'" >> settings/settings.py + echo "ANSIBLE_CONTENT_HOSTNAME='http://$(hostname):8080/pulp/content'" >> settings/settings.py + + - name: 'backend run' + run: | + podman run --publish 8080:80 --name pulp --replace --detach \ + --volume "$(pwd)/settings":/etc/pulp \ + --volume "$(pwd)/pulp_storage":/var/lib/pulp \ + --volume "$(pwd)/pgsql":/var/lib/pgsql \ + --volume "$(pwd)/containers":/var/lib/containers \ + docker.io/pulp/pulp + + - name: 'Install node 20' + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: 'Install python 3.13' + uses: actions/setup-python@v5 + with: + python-version: '3.13' + + - name: 'Cache ~/.npm & ~/.cache/Cypress' + uses: actions/cache@v4 + with: + path: | + ~/.npm + ~/.cache/Cypress + key: npm-${{ hashFiles('package-lock.json') }} + + - name: 'npm install' + run: 'npm install' + + - name: 'gettext extract & compile' + run: | + # production displays unknown translations literally, make sure it's up to date + npm run gettext:extract + npm run gettext:compile + + - name: 'Build UI' + run: | + npm run build + + # save the App.*.js hash for later verification + BUILD_HASH=`ls dist/js/App*js | cut -d. -f2` + echo "BUILD_HASH=${BUILD_HASH}" >> $GITHUB_ENV + + - name: 'Serve UI' + run: | + mkdir -p www/static/ + mv dist www/static/pulp_ui + cd www + echo '{}' > package.json + npm install local-web-server + node_modules/.bin/ws \ + --port 8002 \ + --directory . \ + --spa static/pulp_ui/index.html \ + --rewrite '/api/(.*) -> http://localhost:8080/api/$1' \ + --rewrite '/assets/(.*) -> http://localhost:8080/assets/$1' \ + --rewrite '/auth/(.*) -> http://localhost:8080/auth/$1' \ + --rewrite '/extensions/(.*) -> http://localhost:8080/extensions/$1' \ + --rewrite '/pulp/(.*) -> http://localhost:8080/pulp/$1' \ + --rewrite '/static/rest_framework/(.*) -> http://localhost:8080/static/rest_framework/$1' \ + --rewrite '/v2/(.*) -> http://localhost:8080/v2/$1' \ + --rewrite '/pulp-ui-config.json -> /static/pulp_ui/pulp-ui-config.json' & + + - name: 'Ensure index.html uses the new js' + run: | + echo 'expecting /static/pulp_ui/js/App.'"$BUILD_HASH"'.js' + curl http://localhost:8002/static/pulp_ui/index.html | tee /dev/stderr | grep '/static/pulp_ui/js/App.'"$BUILD_HASH"'.js' + + - name: 'Check status endpoint' + run: | + curl -s -f http://localhost:8080/pulp/api/v3/status/ | jq + + - name: 'Change admin password' + run: | + podman exec -it pulp pulpcore-manager reset-admin-password --password admin + + - name: 'Configure pulp-cli' + run: | + pip install pulp-cli[pygments] + pulp config create --username admin --base-url http://localhost:8080 --password admin + + - name: 'Check login works' + run: | + curl -s -f --retry 8 --retry-all-errors --user admin:admin http://localhost:8080/pulp/api/v3/repositories/python/python/ | jq + + - name: 'Check pulp-cli works' + run: | + pulp user list + + - name: 'Run cypress' + run: | + npm run cypress:chrome + + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: screenshots_and_videos + path: | + cypress/screenshots + cypress/videos + + - name: 'Kill container, show logs' + if: always() + run: | + podman logs pulp + podman kill pulp diff --git a/config/start.config.js b/config/start.config.js index ea807fd1..f395262a 100644 --- a/config/start.config.js +++ b/config/start.config.js @@ -15,6 +15,7 @@ module.exports = webpackBase({ DEV_PROXY: { '/api/': proxyTarget, '/assets/': proxyTarget, + '/auth/': proxyTarget, '/extensions/': proxyTarget, '/pulp/': proxyTarget, '/static/rest_framework/': proxyTarget, diff --git a/cypress.config.js b/cypress.config.js index 36785485..6ffcfe33 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -1,20 +1,12 @@ +// https://on.cypress.io/configuration const { defineConfig } = require('cypress'); module.exports = defineConfig({ - viewportWidth: 1280, - viewportHeight: 800, e2e: { - setupNodeEvents(on, _config) { - if (process.env.CONSOLE_LOG_TO_TERMINAL) { - return require('./cypress/plugins/console-logger').install(on); - } - }, baseUrl: 'http://localhost:8002', - // overridden in cypress.yml - specPattern: 'cypress/e2e/**/*.js', + specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}', }, - // overridden in cypress.yml - screenshotsFolder: 'cypress/screenshots', - // only record videos when running github action in debug mode - video: !!process.env.RUNNER_DEBUG, + video: !!process.env.RUNNER_DEBUG, // only record videos when running github action in debug mode + viewportHeight: 1080, + viewportWidth: 1920, }); diff --git a/cypress.env.json b/cypress.env.json index 7ac118e0..f3e117e7 100644 --- a/cypress.env.json +++ b/cypress.env.json @@ -1,6 +1,6 @@ { - "apiPrefix": "/pulp/api/v3/", - "uiPrefix": "/ui/", + "API_BASE_PATH": "/pulp/api/v3/", + "UI_BASE_PATH": "/ui/", "username": "admin", "password": "admin" } diff --git a/cypress/e2e/approval-modal/approval-multiple-repos-list.js b/cypress/e2e/approval-modal/approval-multiple-repos-list.js deleted file mode 100644 index 434115b0..00000000 --- a/cypress/e2e/approval-modal/approval-multiple-repos-list.js +++ /dev/null @@ -1,155 +0,0 @@ -import { range } from 'lodash'; - -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -function openModal(menu) { - cy.visit(`${uiPrefix}approval`); - cy.contains('Clear all filters').click(); - - if (menu) { - cy.get('[data-cy^="ApprovalRow"] [aria-label="Actions"]').click(); - cy.contains('a', 'Sign and approve').click(); - } else { - cy.contains('[data-cy^="ApprovalRow"] button', 'Sign and approve').click(); - } - - cy.contains('Select repositories'); -} - -function toggleItem(name) { - cy.get('.modal-body [data-cy="compound_filter"] input') - .clear() - .type(name + '{enter}'); - cy.get(`[data-cy="ApproveModal-CheckboxRow-row-${name}"] input`).click(); -} - -const reposList = []; - -describe('Approval Dashboard process with multiple repos', () => { - before(() => { - const max = 11; - range(1, max).forEach((i) => { - reposList.push('repo' + i); - }); - - reposList.push('published'); - - cy.login(); - - cy.request(`${apiPrefix}repositories/ansible/ansible/`).then((data) => { - const list = data.body.results; - list.forEach((repo) => { - if ( - repo.pulp_labels?.pipeline == 'approved' && - repo.name != 'published' - ) { - cy.log('deleting repository' + repo.name); - } - }); - }); - }); - - beforeEach(() => { - cy.login(); - }); - - it('should test paging', () => { - openModal(); - cy.contains('.modal-body .pulp-toolbar', '1 - 10 of 11'); - cy.contains('.modal-body', 'repo1'); - cy.contains('.modal-body', 'published'); - cy.get('.modal-body .pulp-toolbar [data-action="next"]').click(); - cy.contains('.modal-body .pulp-toolbar', '11 - 11 of 11'); - cy.contains('.modal-body', 'repo9'); - }); - - it('should test ordering', () => { - openModal(); - cy.contains('.modal-body', 'repo9').should('not.exist'); - cy.get('.modal-body [data-cy="sort_name"]').click(); - cy.contains('.modal-body', 'repo9'); - cy.contains('.modal-body', 'published').should('not.exist'); - }); - - it('should test filtering', () => { - openModal(); - cy.contains('.modal-body', 'repo9').should('not.exist'); - cy.get('.modal-body [data-cy="compound_filter"] input').type('repo{enter}'); - cy.contains('.modal-body', 'repo9'); - cy.contains('.modal-body', 'repo1'); - cy.contains('.modal-body', 'published').should('not.exist'); - - cy.get('.modal-body [data-cy="compound_filter"] input') - .clear() - .type('repo2{enter}'); - cy.contains('.modal-body', 'repo2'); - cy.contains('.modal-body', 'repo1').should('not.exist'); - cy.contains('.modal-body', 'published').should('not.exist'); - }); - - it('should test select/deselect all/page', () => { - openModal(); - - // deselect all - cy.get('.pulp-toolbar [aria-label="Select"] svg').click(); - cy.contains('a', 'Deselect all (0 items)').click(); - reposList.forEach((repo) => { - cy.contains('[aria-label="Label group category"]', repo).should( - 'not.exist', - ); - }); - - // select page - cy.get('.pulp-toolbar [aria-label="Select"] svg').click(); - cy.contains('a', 'Select page (10 items)').click(); - cy.contains('.pf-v5-c-label.pf-m-overflow', 'more').click(); - - reposList.forEach((repo) => { - if (repo != 'repo9') { - cy.contains('[aria-label="Label group category"]', repo); - } else { - cy.contains('[aria-label="Label group category"]', repo).should( - 'not.exist', - ); - } - }); - - // select repo9 - toggleItem('repo9'); - cy.contains('Clear all filters').click(); - - // deselect page and repo9 should remain here - cy.get('.pulp-toolbar [aria-label="Select"] svg').click(); - cy.contains('a', 'Deselect page (10 items)').click(); - - reposList.forEach((repo) => { - if (repo != 'repo9') { - cy.contains('[aria-label="Label group category"]', repo).should( - 'not.exist', - ); - } else { - cy.contains('[aria-label="Label group category"]', repo); - } - }); - }); - - it('should test selection', () => { - openModal(); - toggleItem('repo1'); - toggleItem('published'); - cy.contains('[aria-label="Label group category"]', 'repo1'); - cy.contains('[aria-label="Label group category"]', 'published'); - - toggleItem('published'); - cy.contains('[aria-label="Label group category"]', 'published').should( - 'not.exist', - ); - - toggleItem('published'); - cy.get('[aria-label="Close published"]').click(); - cy.contains('[aria-label="Label group category"]', 'published').should( - 'not.exist', - ); - }); -}); diff --git a/cypress/e2e/approval-modal/approval-multiple-repos.js b/cypress/e2e/approval-modal/approval-multiple-repos.js deleted file mode 100644 index 36aa71ce..00000000 --- a/cypress/e2e/approval-modal/approval-multiple-repos.js +++ /dev/null @@ -1,159 +0,0 @@ -import { range } from 'lodash'; - -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -function openModal(menu) { - cy.visit(`${uiPrefix}approval`); - cy.contains('Clear all filters').click(); - - if (menu) { - cy.get('[data-cy^="ApprovalRow"] [aria-label="Actions"]').click(); - cy.contains('a', 'Sign and approve').click(); - } else { - cy.contains('[data-cy^="ApprovalRow"] button', 'Sign and approve').click(); - } - - cy.contains('Select repositories'); -} - -function toggleItem(name) { - cy.get('.modal-body [data-cy="compound_filter"] input') - .clear() - .type(name + '{enter}'); - cy.get(`[data-cy="ApproveModal-CheckboxRow-row-${name}"] input`).click(); -} - -function menuActionClick(repo, action) { - cy.get( - `[data-cy="ApprovalRow-${repo}-namespace-collection1"] [aria-label="Actions"]`, - ).click(); - cy.contains('[data-cy="kebab-toggle"] a', action).click(); -} - -function rejectItem(repo) { - menuActionClick(repo, 'Reject'); - cy.contains( - 'Certification status for collection "namespace collection1 v1.0.0" has been successfully updated.', - { timeout: 10000 }, - ); - cy.visit(`${uiPrefix}approval`); - cy.contains('Clear all filters').click(); - cy.contains( - `[data-cy="ApprovalRow-rejected-namespace-collection1"]`, - 'Rejected', - ); -} - -const reposList = []; - -describe('Approval Dashboard process with multiple repos', () => { - before(() => { - const max = 11; - range(1, max).forEach((i) => { - reposList.push('repo' + i); - }); - - reposList.push('published'); - - cy.login(); - - cy.request(`${apiPrefix}repositories/ansible/ansible/`).then((data) => { - const list = data.body.results; - list.forEach((repo) => { - if ( - repo.pulp_labels?.pipeline == 'approved' && - repo.name != 'published' - ) { - cy.log('deleting repository' + repo.name); - } - }); - }); - }); - - beforeEach(() => { - cy.login(); - }); - - it('should contains no colletctions in list', () => { - cy.visit(`${uiPrefix}collections`); - cy.contains('No collections yet'); - }); - - it('should approve, reject and reapprove', () => { - openModal(); - toggleItem('repo1'); - toggleItem('repo2'); - toggleItem('published'); - cy.contains('button', 'Select').click(); - cy.contains( - 'Certification status for collection "namespace collection1 v1.0.0" has been successfully updated.', - { timeout: 20000 }, - ); - - cy.visit(`${uiPrefix}approval`); - cy.contains('No results found'); - cy.contains('Clear all filters').click(); - cy.contains('[aria-label="Collection versions"]', 'repo1'); - cy.contains('[aria-label="Collection versions"]', 'repo2'); - cy.contains('[aria-label="Collection versions"]', 'Published'); - - rejectItem('repo1'); - rejectItem('published'); - - // 2 items should be left there - cy.contains('.pulp-toolbar', '1 - 2 of 2'); - cy.get('[data-cy="ApprovalRow-rejected-namespace-collection1"]'); - cy.get('[data-cy="ApprovalRow-repo2-namespace-collection1"]'); - cy.get('[data-cy="ApprovalRow-repo1-namespace-collection1"]').should( - 'not.exist', - ); - cy.get('[data-cy="ApprovalRow-published-namespace-collection1"]').should( - 'not.exist', - ); - - // reapprove - menuActionClick('rejected', 'Sign and approve'); - cy.contains('Select repositories'); - toggleItem('repo1'); - cy.contains('button', 'Select').click(); - cy.contains( - 'Certification status for collection "namespace collection1 v1.0.0" has been successfully updated.', - { timeout: 20000 }, - ); - - cy.visit(`${uiPrefix}approval`); - cy.contains('Clear all filters').click(); - cy.contains('.pulp-toolbar', '1 - 2 of 2'); - cy.get('[data-cy="ApprovalRow-repo2-namespace-collection1"]'); - cy.get('[data-cy="ApprovalRow-repo1-namespace-collection1"]'); - cy.get('[data-cy="ApprovalRow-published-namespace-collection1"]').should( - 'not.exist', - ); - cy.get('[data-cy="ApprovalRow-rejected-namespace-collection1"]').should( - 'not.exist', - ); - }); - - it('should be able to approve from different staging repo', () => { - cy.visit(`${uiPrefix}approval`); - cy.get('[data-cy="ApprovalRow-staging2-namespace-collection1"]'); - - openModal(); - toggleItem('repo1'); - toggleItem('repo2'); - toggleItem('published'); - cy.contains('button', 'Select').click(); - cy.contains( - 'Certification status for collection "namespace collection1 v1.0.0" has been successfully updated.', - { timeout: 20000 }, - ); - - cy.visit(`${uiPrefix}approval`); - cy.contains('No results found'); - cy.contains('Clear all filters').click(); - cy.contains('[aria-label="Collection versions"]', 'repo1'); - cy.contains('[aria-label="Collection versions"]', 'repo2'); - cy.contains('[aria-label="Collection versions"]', 'Published'); - }); -}); diff --git a/cypress/e2e/approval/approval-dashboard-list.js b/cypress/e2e/approval/approval-dashboard-list.js deleted file mode 100644 index 3d2ee183..00000000 --- a/cypress/e2e/approval/approval-dashboard-list.js +++ /dev/null @@ -1,152 +0,0 @@ -import { range } from 'lodash'; - -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Approval Dashboard list tests for sorting, paging and filtering', () => { - const items = []; - - function loadData() { - const intercept_url = `${apiPrefix}v3/plugin/ansible/search/collection-versions/?order_by=-pulp_created&offset=0&limit=100`; - - cy.visit(`${uiPrefix}approval?page_size=100`); - cy.intercept('GET', intercept_url).as('data'); - cy.contains('button', 'Clear all filters').click(); - - cy.wait('@data').then(({ response: { body } }) => { - body.data.forEach((record) => { - items.push(record.collection_version.name); - }); - items.sort(); - }); - } - - before(() => { - cy.login(); - loadData(); - }); - - beforeEach(() => { - cy.login(); - cy.visit(`${uiPrefix}approval`); - cy.contains('button', 'Clear all filters').click(); - }); - - it('should contains all columns', () => { - ['Namespace', 'Collection', 'Version', 'Date created', 'Status'].forEach( - (item) => { - cy.get('[data-cy="SortTable-headers"]').contains(item); - }, - ); - }); - - it('should sort & page', () => { - cy.get('[data-cy="sort_name"]').click(); - cy.get('[data-cy="sort_name"]').click(); - - cy.get('[data-cy="body"]').contains(items[0]); - - cy.get('[data-cy="body"]') - .get('[aria-label="Go to next page"]:first') - .click(); - cy.get('[data-cy="body"]').contains(items[10]); - }); - - it('should sort collection', () => { - cy.get('[data-cy="sort_name"]').click(); - cy.get('[data-cy="body"]').contains('approval'); - - cy.get('[data-cy^="ApprovalRow"]:first').contains(items.at(-1)); - cy.get('[data-cy^="ApprovalRow"]').contains(items.at(-2)); - cy.get('[data-cy^="ApprovalRow"]').contains(items.at(-3)); - }); - - it('should see time informations', () => { - cy.contains('[data-cy="body"]', 'a few seconds ago'); - }); - - it('should filter collection', () => { - cy.get('[data-cy="body"] [data-cy="compound_filter"] button:first').click(); - cy.contains( - '[data-cy="body"] [data-cy="compound_filter"] a', - 'Collection name', - ).click(); - cy.get('[data-cy="sort_name"]').click(); - cy.get('[data-cy="sort_name"]').click(); - - cy.get('[data-cy="body"] [data-cy="compound_filter"] input').type( - 'approval_collection_test0{enter}', - ); - cy.get('[data-cy="body"]').contains('approval_collection_test0'); - cy.get('[data-cy="body"]') - .contains('approval_collection_test1') - .should('not.exist'); - }); - - it('should filter collection and namespace together', () => { - cy.get('[data-cy="body"] [data-cy="compound_filter"] button:first').click(); - cy.contains( - '[data-cy="body"] [data-cy="compound_filter"] a', - 'Collection name', - ).click(); - cy.get('[data-cy="body"] .pulp-toolbar input').type( - 'approval_collection_test0{enter}', - ); - - cy.get('[data-cy="body"] .pulp-toolbar button:first').click(); - cy.contains( - '[data-cy="body"] [data-cy="compound_filter"] a', - 'Namespace', - ).click(); - cy.get('[data-cy="body"] [data-cy="compound_filter"] input').type( - 'approval_namespace_test{enter}', - ); - - cy.get('[data-cy="sort_name"]').click(); - cy.get('[data-cy="sort_name"]').click(); - - cy.get('[data-cy="body"]').contains('approval_collection_test0'); - cy.get('[data-cy="body"]') - .contains('approval_collection_test1') - .should('not.exist'); - cy.get('[data-cy="body"]') - .contains('approval_namespace_test_additional_data') - .should('not.exist'); - }); - - it('should filter non existing namespace and not show any data', () => { - cy.get('[data-cy="body"] [data-cy="compound_filter"] button:first').click(); - cy.contains( - '[data-cy="body"] [data-cy="compound_filter"] a', - 'Namespace', - ).click(); - cy.get('[data-cy="body"] [data-cy="compound_filter"] input').type( - 'namespace1354564sdfhdfhhfdf{enter}', - ); - - cy.get('[data-cy="body"]').contains('No results found'); - }); - - it('should set page size', () => { - cy.get('[data-cy="body"]') - .get('[data-ouia-component-type="PF5/Pagination"] button:first') - .click(); - cy.get('[data-cy="body"]').contains('20 per page').click(); - - cy.get('[data-cy="sort_name"]').click(); - cy.get('[data-cy="sort_name"]').click(); - - range(11).forEach((i) => { - cy.get('[data-cy="body"]').contains(items[i]); - }); - }); - - it('should redirect to import logs', () => { - cy.get( - '[data-cy="kebab-toggle"]:first button[aria-label="Actions"]', - ).click(); - cy.contains('View Import Logs').click(); - cy.contains('My imports'); - cy.get('.import-list'); - }); -}); diff --git a/cypress/e2e/approval/approval-process.js b/cypress/e2e/approval/approval-process.js deleted file mode 100644 index 58390b26..00000000 --- a/cypress/e2e/approval/approval-process.js +++ /dev/null @@ -1,74 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); -const apiPrefix = Cypress.env('apiPrefix'); - -describe('Approval Dashboard process', () => { - beforeEach(() => { - cy.login(); - }); - - it('should test the whole approval process', () => { - cy.visit(`${uiPrefix}collections`); - cy.contains('No collections yet'); - - // should approve - cy.visit(`${uiPrefix}approval`); - cy.contains('[data-cy^="ApprovalRow"]', 'Needs review'); - cy.contains('[data-cy^="ApprovalRow"] button', 'Sign and approve').click(); - cy.contains('.pulp-section', 'No results found', { timeout: 8000 }); - cy.visit(`${uiPrefix}approval`); - cy.contains('button', 'Clear all filters').click(); - cy.contains('[data-cy^="ApprovalRow"]', 'Signed and approved'); - - // should see item in collections - cy.visit(`${uiPrefix}collections?page_size=100`); - cy.contains('.collection-container', 'appp_c_test1'); - - // should reject - cy.visit(`${uiPrefix}approval`); - cy.contains('button', 'Clear all filters').click(); - cy.get('[data-cy="kebab-toggle"]:first button[aria-label="Actions"]').click( - { force: true }, - ); - cy.contains('Reject').click({ force: true }); - cy.contains('[data-cy^="ApprovalRow"]', 'Rejected'); - - // should not see items in collections - cy.visit(`${uiPrefix}collections`); - cy.contains('No collections yet'); - }); - - it('collection should be uploaded into different repo', () => { - cy.login(); - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/ansible/search/collection-versions/?namespace=*`, - ).as('upload'); - cy.menuGo('Collections > Namespaces'); - - cy.get(`a[href="${uiPrefix}namespaces/ansible/"]`).click(); - cy.contains('Upload collection').click(); - cy.fixture('collections/ansible-posix-1.4.0.tar.gz', 'binary') - .then(Cypress.Blob.binaryStringToBlob) - .then((fileContent) => { - cy.get('input[type="file"]').attachFile({ - fileContent, - fileName: 'ansible-posix-1.4.0.tar.gz', - mimeType: 'application/gzip', - }); - }); - cy.get('[data-cy="ApproveModal-RadioRow-row-staging2"] input').click(); - cy.get('[data-cy="confirm-upload"]').click(); - cy.wait('@upload'); - cy.wait(10000); - cy.contains('My imports'); - cy.get('.pf-v5-c-label__content').contains('Running').should('exist'); - cy.wait('@upload', { timeout: 10000 }); - cy.wait(5000); - cy.get('.pf-v5-c-label__content').contains('Failed').should('not.exist'); - cy.get('.pf-v5-c-label__content').contains('Completed').should('exist'); - cy.visit(`${uiPrefix}repo/staging2/ansible/posix/`); - cy.contains('ansible'); - cy.contains('posix'); - cy.contains('1.4.0'); - }); -}); diff --git a/cypress/e2e/approval/collection-approval.js b/cypress/e2e/approval/collection-approval.js deleted file mode 100644 index 1e9e506d..00000000 --- a/cypress/e2e/approval/collection-approval.js +++ /dev/null @@ -1,56 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -describe('tests the approval list screen ', () => { - beforeEach(() => { - cy.login(); - cy.visit(`${uiPrefix}approval`); - }); - - it('has a default Needs Review filter', () => { - cy.get('.pf-v5-c-chip-group__list').contains('Needs Review'); - }); - - it('rejects certification status and approves it again', () => { - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/ansible/search/collection-versions/?order_by=-pulp_created&offset=0&limit=10`, - ).as('reload'); - cy.get('.pf-v5-c-chip button[data-ouia-component-id="close"]').click(); - cy.wait('@reload'); - - // reject - cy.get('button[aria-label="Actions"]:first').click(); - cy.contains('Reject').click(); - cy.contains('[data-cy^="ApprovalRow"]:first-child', 'Rejected'); - - // approve - cy.get('button[aria-label="Actions"]:first').click(); - cy.contains('Sign and approve').click(); - cy.contains('[data-cy^="ApprovalRow"]:first-child', 'Signed and approved'); - }); - - it('view the imports logs', () => { - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/ansible/search/collection-versions/?order_by=-pulp_created&offset=0&limit=10`, - ).as('reload'); - cy.get('.pf-v5-c-chip button[data-ouia-component-id="close"]').click(); - cy.wait('@reload'); - - // imports page - - cy.get('button[aria-label="Actions"]:first').click(); - cy.intercept( - 'GET', - `${apiPrefix}_ui/v1/imports/collections/?namespace=ansible&name=network&version=1.0.0&sort=-created&offset=0&limit=10`, - ).as('imports'); - cy.contains('View Import Logs').click(); - cy.wait('@imports'); - cy.contains('My imports'); - cy.get('[placeholder="Select namespace"]').should('have.value', 'ansible'); - - cy.get('.pf-v5-c-chip-group__list').contains('network'); - cy.get('.pf-v5-c-chip-group').contains('1.0.0'); - }); -}); diff --git a/cypress/e2e/approval/signing.js b/cypress/e2e/approval/signing.js deleted file mode 100644 index 55ebcb69..00000000 --- a/cypress/e2e/approval/signing.js +++ /dev/null @@ -1,39 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); - -describe('signing versions - auto sign on approval', () => { - beforeEach(() => { - cy.login(); - }); - - it('has the switch to sync only certified repos', () => { - cy.visit(`${uiPrefix}ansible/remotes`); - cy.get('[aria-label="Actions"]:first').click(); // click the kebab menu on the 'community' repo - cy.contains('Edit').click(); - cy.contains('Show advanced options').click(); - cy.get('#signed_only').should('exist'); - }); - - it('signs when the Sign and Approve button is pressed', () => { - cy.visit(`${uiPrefix}approval`); - - // Check if the button is correctly worded - cy.get('[data-cy="approve-button"]').should('contain', 'Sign and approve'); - - // Sign the first collection - cy.get('[data-cy="approve-button"]').first().click(); - cy.wait(10000); - - // Go and check if it is signed in the collections - cy.visit(`${uiPrefix}collections`); - cy.get('[data-cy="signature-badge"]', { timeout: 20000 }).should( - 'have.length', - 1, - ); - cy.get('[data-cy="signature-badge"]').first().should('contain', 'Signed'); - - // Optimization: check the signature button too here - cy.visit(`${uiPrefix}repo/published/autosign_test/test_collection`); - cy.get('[data-cy="signature-badge"]').first().should('contain', 'Signed'); - cy.get('[data-cy="toggle-signature-button"]').should('be.visible'); - }); -}); diff --git a/cypress/e2e/collections/collection-detail.js b/cypress/e2e/collections/collection-detail.js deleted file mode 100644 index 6900f2b6..00000000 --- a/cypress/e2e/collections/collection-detail.js +++ /dev/null @@ -1,157 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Collection detail', () => { - const baseURL = `${uiPrefix}repo/published/collection_detail_test_namespace/collection_detail_test_collection`; - - function deprecate() { - cy.openHeaderKebab(); - cy.contains('Deprecate').click(); - cy.contains('This collection has been deprecated.', { timeout: 10000 }); - } - - function undeprecate() { - cy.openHeaderKebab(); - cy.contains('Undeprecate').click(); - cy.contains('This collection has been deprecated.', { - timeout: 10000, - }).should('not.exist'); - } - - beforeEach(() => { - cy.login(); - }); - - it('can Deprecate', () => { - cy.visit(baseURL); - deprecate(); - }); - - it('can Undeprecate', () => { - cy.visit(baseURL); - undeprecate(); - }); - - it('should change the url when clicking on the tabs', () => { - cy.visit(baseURL); - - const tabs = [ - { - name: 'Documentation', - url: `${baseURL}/docs`, - }, - { - name: 'Import log', - url: `${baseURL}/import-log`, - }, - { - name: 'Dependencies', - url: `${baseURL}/dependencies`, - }, - { - name: 'Contents', - url: `${baseURL}/content`, - }, - { - name: 'Install', - url: `${baseURL}`, - }, - ]; - - tabs.forEach((tab) => { - cy.contains('li a span', tab.name).click(); - cy.url().should('include', tab.url); - // All tabs contain the repo link - cy.contains('a', 'Repo'); - - // better synchronization, wait for the rest of the page to load - - if (tab.name == 'Documentation') { - cy.contains('.pulp-docs-container', 'Documentation'); - } - - if (tab.name == 'Import log') { - cy.contains('.pulp-section', 'Approval status', { - timeout: 10000, - }); - } - - if (tab.name == 'Contents') { - cy.contains('.pulp-section', 'Description'); - } - - if (tab.name == 'Dependencies') { - cy.contains('.pulp-section', 'No dependencies'); - } - - if (tab.name == 'Install') { - cy.contains('.pulp-section', 'License'); - } - }); - }); - - it('should have working UI on install tab', () => { - cy.visit(baseURL); - // should have Install, License and Installation strings, and correct docs link - cy.get('.pulp-section').contains('Install'); - cy.get('.pulp-section').contains('License'); - cy.get('.pulp-section').contains('Installation'); - - cy.get('.pulp-section').contains( - `a[href="${uiPrefix}repo/published/collection_detail_test_namespace/collection_detail_test_collection/docs/"]`, - 'Go to documentation', - ); - - /* - * This test needs some external library and custom command to test if the download had started. - * For now it fails if the button is not there. - */ - // should be able to download the tarball - cy.get('[data-cy="download-collection-tarball-button"]').contains( - 'Download tarball', - ); - - // should have the correct tags - cy.get('[data-cy="tag"]').should('have.length', 1); - cy.get('[data-cy="tag"]:first').contains('tools'); - - // should have the correct ansible version - cy.get('[data-cy="ansible-requirement"]').contains('>=2'); - }); - - it('should have working UI on docs tab', () => { - cy.visit(`${baseURL}/docs`); - // should have the search field - cy.get('.pulp-section').get('input[aria-label="find-content"'); - - // should have Readme menu item - cy.get('.pulp-docs-sidebar').contains('Readme'); - - // should still show the readme when searching readme - cy.get('input[aria-label="find-content"').type('readme'); - cy.get('.pulp-docs-sidebar').contains('Readme'); - - // should not display readme if searching for no entry - cy.get('input[aria-label="find-content"').type('no entry'); - cy.get('.pulp-docs-sidebar').not(':contains("Readme")'); - }); - - it('should have a search field and the table headers on contents tab', () => { - cy.visit(`${baseURL}/content`); - cy.get('.pulp-section').get('input[aria-label="find-content"'); - cy.get('.pulp-section').contains('th', 'Name'); - cy.get('.pulp-section').contains('th', 'Type'); - cy.get('.pulp-section').contains('th', 'Description'); - }); - - it('should display import log tab', () => { - cy.visit(`${baseURL}/import-log`); - cy.get('.pulp-section').get('.title-bar'); - cy.get('.pulp-section').get('.message-list'); - }); - - it('should display "No Dependencies" when opening the tab', () => { - cy.visit(`${baseURL}/dependencies`); - cy.get('.pulp-section').contains('Dependencies'); - cy.get('.pulp-section').contains('No dependencies'); - }); -}); diff --git a/cypress/e2e/collections/collection-upload.js b/cypress/e2e/collections/collection-upload.js deleted file mode 100644 index db6b75db..00000000 --- a/cypress/e2e/collections/collection-upload.js +++ /dev/null @@ -1,122 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Collection Upload Tests', () => { - const username = 'testUser'; - const userPassword = 'I am a complicated passw0rd'; - - it('should not upload new collection version in collection list when user does not have permissions', () => { - cy.login(username, userPassword); - cy.visit( - `${uiPrefix}collections?page_size=10&view_type=list&keywords=testcollection`, - ); - cy.contains('testcollection'); - cy.contains('Upload new version').should('not.exist'); - }); - - it('should not upload new collection version in collection list/cards when user does not have permissions', () => { - cy.login(username, userPassword); - cy.visit( - `${uiPrefix}collections?page_size=10&view_type=card&keywords=testcollection`, - ); - cy.contains('testcollection'); - cy.get('[aria-label="Actions"]').should('not.exist'); - }); - - it('should not upload new collection version in collection detail when user does not have permissions', () => { - cy.login(username, userPassword); - cy.visit(`${uiPrefix}repo/published/testspace/testcollection`); - cy.contains('testcollection'); - cy.openHeaderKebab(); - cy.contains('Upload new version').should('not.exist'); - }); - - it('should see upload new collection version in collection list when user does have permissions', () => { - cy.login(); - cy.visit( - `${uiPrefix}collections?page_size=10&view_type=list&keywords=testcollection`, - ); - cy.contains('testcollection'); - cy.contains('Upload new version').click(); - cy.contains('New version of testspace.testcollection'); - - cy.visit( - `${uiPrefix}collections?page_size=10&view_type=card&keywords=testcollection`, - ); - cy.contains('testcollection'); - cy.get('button[aria-label="Actions"]').click(); - cy.contains('Upload new version').click(); - cy.contains('New version of testspace.testcollection'); - }); - - it('should see upload new collection version in collection detail when user does have permissions', () => { - cy.login(); - cy.visit(`${uiPrefix}repo/published/testspace/testcollection`); - cy.contains('testcollection'); - cy.openHeaderKebab(); - cy.contains('Upload new version').click(); - cy.contains('New version of testspace.testcollection'); - }); - - it('user should not be able to upload new collection without permissions', () => { - cy.login(username, userPassword); - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/ansible/search/collection-versions/?namespace=*`, - ).as('upload'); - cy.menuGo('Collections > Namespaces'); - - cy.get(`a[href="${uiPrefix}namespaces/ansible/"]`).click(); - cy.contains('Upload collection').should('not.exist'); - }); - - it('collection should be uploaded', () => { - cy.login(); - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/ansible/search/collection-versions/?namespace=*`, - ).as('upload'); - cy.menuGo('Collections > Namespaces'); - - cy.get(`a[href="${uiPrefix}namespaces/ansible/"]`).click(); - cy.contains('Upload collection').click(); - cy.fixture('collections/ansible-posix-1.4.0.tar.gz', 'binary') - .then(Cypress.Blob.binaryStringToBlob) - .then((fileContent) => { - cy.get('input[type="file"]').attachFile({ - fileContent, - fileName: 'ansible-posix-1.4.0.tar.gz', - mimeType: 'application/gzip', - }); - }); - cy.get('[data-cy="confirm-upload"]').click(); - cy.wait('@upload'); - cy.contains('My imports'); - cy.get('.pf-v5-c-label__content').contains('Completed', { timeout: 15000 }); - cy.get('.pf-v5-c-label__content').contains('Failed').should('not.exist'); - cy.get('.pf-v5-c-label__content').contains('Running').should('not.exist'); - }); - - it('should not upload new collection version when user does not have permissions', () => { - cy.login(username, userPassword); - cy.visit(`${uiPrefix}namespaces/testspace`); - - cy.get('[data-cy="CollectionList-name"]').contains('testcollection'); - cy.contains('Upload new version').should('not.exist'); - }); - - it('should deprecate let user deprecate and undeprecate collections', () => { - cy.login(); - cy.visit(`${uiPrefix}namespaces/testspace`); - cy.get('[data-cy=collection-kebab]').first().click(); - cy.contains('Deprecate').click(); - cy.visit(`${uiPrefix}namespaces/testspace`); - cy.contains('DEPRECATED'); - - cy.visit(`${uiPrefix}namespaces/testspace`); - cy.get('[data-cy=collection-kebab]').first().click(); - cy.contains('Undeprecate').click(); - cy.visit(`${uiPrefix}namespaces/testspace`); - cy.contains('DEPRECATED').should('not.exist'); - }); -}); diff --git a/cypress/e2e/collections/collection.js b/cypress/e2e/collections/collection.js deleted file mode 100644 index 35dbc539..00000000 --- a/cypress/e2e/collections/collection.js +++ /dev/null @@ -1,128 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -describe('collection tests', () => { - beforeEach(() => { - cy.login(); - }); - - it('deletes an entire collection', () => { - cy.visit(`${uiPrefix}repo/published/test_namespace/test_collection`); - - cy.openHeaderKebab(); - cy.get('[data-cy=delete-collection]').click(); - cy.get('input[id=delete_confirm]').click(); - cy.get('button').contains('Delete').click(); - cy.contains('No collections yet', { timeout: 10000 }); - }); - - it('deletes a collection version', () => { - cy.visit(`${uiPrefix}collections`); - - cy.intercept('GET', `${apiPrefix}_ui/v1/namespaces/my_namespace/?*`).as( - 'reload', - ); - cy.get( - `a[href*="${uiPrefix}repo/published/my_namespace/my_collection"]`, - ).click(); - cy.openHeaderKebab(); - cy.get('[data-cy=delete-collection-version]').click(); - cy.get('input[id=delete_confirm]').click(); - cy.get('button').contains('Delete').click(); - cy.wait('@reload', { timeout: 50000 }); - cy.wait(5000); - cy.get('[data-cy="AlertList"] h4[class=pf-v5-c-alert__title]').should( - 'have.text', - 'Success alert:Collection "my_collection v1.0.0" has been successfully deleted.', - ); - }); - - it('should copy collection version to validated repository', () => { - const rand = Math.floor(Math.random() * 9999999); - const namespace = `foo_${rand}`; - const collection = `bar_${rand}`; - cy.visit(`${uiPrefix}repo/published/${namespace}/${collection}`); - - cy.openHeaderKebab(); - cy.get( - '[data-cy="copy-collection-version-to-repository-dropdown"]', - ).click(); - - cy.contains('Select repositories'); - cy.get( - '[data-cy="ApproveModal-CheckboxRow-row-published"] .pf-v5-c-table__check input', - ).should('be.disabled'); - - cy.get("[aria-label='name__icontains']").type('validate{enter}'); - cy.get( - "[data-cy='ApproveModal-CheckboxRow-row-validated'] .pf-v5-c-table__check input", - ).check(); - - cy.get('.pf-m-primary').contains('Select').click(); - - cy.get('[data-cy="AlertList"]').contains( - `Started adding ${namespace}.${collection} v1.0.0 from "published" to repository "validated".`, - ); - cy.get('[data-cy="AlertList"]').contains('detail page').click(); - cy.contains('Completed'); - }); - - it('deletes a collection from repository', () => { - cy.visit(`${uiPrefix}collections?view_type=list`); - cy.contains('Collections'); - cy.contains('[data-cy="CollectionListItem"]', 'Published'); - cy.contains('[data-cy="CollectionListItem"]', 'repo2'); - - cy.get('.collection-container [aria-label="Actions"]:first').click({ - force: true, - }); - cy.contains('Remove collection from repository').click(); - cy.get('input[id=delete_confirm]').click(); - cy.get('button').contains('Delete').click(); - cy.contains( - 'Collection "test_repo_collection2" has been successfully deleted.', - { - timeout: 10000, - }, - ); - cy.contains('[data-cy="CollectionListItem"]', 'repo2'); - cy.contains('[data-cy="CollectionListItem"]', 'Published').should( - 'not.exist', - ); - }); - - it('deletes a collection version from repository', () => { - cy.visit(`${uiPrefix}collections?view_type=list`); - cy.contains('Collections'); - cy.contains('[data-cy="CollectionListItem"]', 'Published'); - cy.contains('[data-cy="CollectionListItem"]', 'repo2'); - - cy.visit( - `${uiPrefix}repo/repo2/test_namespace/test_repo_collection_version2/?version=1.0.0`, - ); - - cy.openHeaderKebab(); - cy.contains('Remove version 1.0.0 from repository').click(); - cy.get('input[id=delete_confirm]').click(); - cy.get('button').contains('Delete').click(); - cy.contains( - 'Collection "test_repo_collection_version2 v1.0.0" has been successfully deleted.', - { - timeout: 10000, - }, - ); - - cy.visit( - `${uiPrefix}repo/repo2/test_namespace/test_repo_collection_version2/?version=1.0.0`, - ); - cy.contains(`We couldn't find the page you're looking for!`); - - cy.visit( - `${uiPrefix}repo/published/test_namespace/test_repo_collection_version2/?version=1.0.0`, - ); - cy.contains('test_repo_collection_version2'); - cy.contains(`We couldn't find the page you're looking for!`).should( - 'not.exist', - ); - }); -}); diff --git a/cypress/e2e/collections/collections-list.js b/cypress/e2e/collections/collections-list.js deleted file mode 100644 index 5f9f0ac1..00000000 --- a/cypress/e2e/collections/collections-list.js +++ /dev/null @@ -1,145 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Collections list Tests', () => { - function deprecate(list) { - const container = list ? '.pulp-list' : '.pulp-cards'; - - cy.get('[data-cy=pulp-list-toolbar]') - .get('[aria-label="keywords"]:first') - .type('my_collection0{enter}'); - cy.get(container).contains('my_collection2').should('not.exist'); - cy.get(container).contains('my_collection0'); - - cy.get('.collection-container [aria-label="Actions"]').click(); - cy.contains('Deprecate').click(); - cy.contains('No results found', { timeout: 10000 }); - } - - function undeprecate() { - cy.visit(`${uiPrefix}repo/published/my_namespace/my_collection0`); - cy.contains('This collection has been deprecated.'); - cy.openHeaderKebab(); - cy.contains('Undeprecate').click(); - cy.contains('This collection has been deprecated.', { - timeout: 10000, - }).should('not.exist'); - } - - function undeprecateIfDeprecated() { - // undeprecate collection if deprecated from previous repeated run (otherwise, tests fails) - // that is because when you deprecate, delete collection and upload it again, the collection - // stays deprecated - const request_url = `${apiPrefix}_ui/v1/repo/published/?limit=1&keywords=my_collection0&offset=0"`; - - cy.request(request_url).then((data) => { - const deprecated = data.body.data[0].deprecated; - if (deprecated) { - undeprecate(); - } - }); - } - - beforeEach(() => { - cy.login(); - cy.visit(`${uiPrefix}collections`); - cy.contains('Collections'); - }); - - it('checks if its deprecated and if yes, undeprecate it', () => { - undeprecateIfDeprecated(); - }); - - it('can deprecate', () => { - cy.get('[data-cy="view_type_list"] svg').click(); - deprecate(true); - }); - - it('can undeprecate', () => { - cy.get('[data-cy="view_type_list"] svg').click(); - undeprecate(); - }); - - it('can deprecate in Cards', () => { - cy.get('[data-cy="view_type_card"] svg').click(); - deprecate(false); - }); - - it('can undeprecate in Cards', () => { - cy.get('[data-cy="view_type_card"] svg').click(); - undeprecate(false); - }); - - it('paging', () => { - // there should be 11 items in db, 10 per page + 1 view more - cy.get('.collection-container') - .get('.pulp-c-card-collection-container') - .should('have.length', 11); - - cy.get('.pulp-cards').get('[aria-label="Go to next page"]:first').click(); - cy.get('.collection-container') - .get('.pulp-c-card-collection-container') - .should('have.length', 1); - }); - - it('filter', () => { - cy.get('.pulp-cards') - .get('[aria-label="keywords"]:first') - .type('my_collection0{enter}'); - cy.get('.pulp-cards').contains('my_collection0'); - cy.get('.pulp-cards').contains('my_collection1').should('not.exist'); - }); - - it('set page size', () => { - cy.get('.pulp-cards') - .get('[data-ouia-component-type="PF5/Pagination"] button:first') - .click(); - cy.get('.pulp-cards').get('[data-action="per-page-20"]').click(); - - cy.get('.collection-container') - .get('.pulp-c-card-collection-container') - .should('have.length', 11); - }); - - it('Cards/List switch', () => { - cy.get('[data-cy="view_type_list"] svg').click(); - - cy.get('[data-cy="CollectionListItem"]').should('have.length', 10); - }); - - it('Can delete collection in collection list', () => { - cy.get('[data-cy="view_type_list"] svg').click(); - cy.get('[data-cy=pulp-list-toolbar]') - .get('[aria-label="keywords"]:first') - .type('my_collection0{enter}'); - cy.get('.pulp-list').contains('my_collection2').should('not.exist'); - cy.get('.pulp-list').contains('my_collection0'); - - cy.get('.collection-container [aria-label="Actions"]').click(); - cy.contains('Delete collection from system').click(); - cy.get('[data-cy=modal_checkbox] input').click(); - cy.get('[data-cy=delete-button] button').click(); - cy.contains('Collection "my_collection0" has been successfully deleted.', { - timeout: 15000, - }); - cy.contains('No results found'); - }); - - it('Can delete collection in namespace collection list', () => { - cy.visit(`${uiPrefix}namespaces/my_namespace`); - cy.get('[data-cy=pulp-list-toolbar]') - .get('[aria-label="keywords"]:first') - .type('my_collection1{enter}'); - - cy.get('.pulp-section').contains('my_collection1'); - cy.get('.pulp-section [aria-label="Actions"]').click(); - cy.contains('Delete collection from system').click(); - cy.get('[data-cy=modal_checkbox] input').click(); - cy.get('[data-cy=delete-button] button').click(); - - cy.contains('Collection "my_collection1" has been successfully deleted.', { - timeout: 15000, - }); - cy.contains('No results found'); - }); -}); diff --git a/cypress/e2e/namespaces/docs-menu.js b/cypress/e2e/namespaces/docs-menu.js deleted file mode 100644 index 98855cd3..00000000 --- a/cypress/e2e/namespaces/docs-menu.js +++ /dev/null @@ -1,23 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Documentation dropdown', () => { - beforeEach(() => { - cy.visit(uiPrefix); - cy.login(); - }); - - it('user can open docs dropdown menu', () => { - cy.get('[data-cy="docs-dropdown"]').click(); - cy.get('.pf-v5-c-dropdown__menu').contains('Documentation'); - cy.get('.pf-v5-c-dropdown__menu').contains('About'); - }); - - it('user can toggle about modal', () => { - cy.get('[data-cy="docs-dropdown"]').click(); - cy.get('.pf-v5-c-dropdown__menu').contains('About').click(); - cy.get('.pf-v5-c-about-modal-box').should('be.visible'); - cy.get('h1').contains('Galaxy NG'); - cy.get('[aria-label="Close Dialog"]').click(); - cy.get('.pf-v5-c-about-modal-box').should('not.exist'); - }); -}); diff --git a/cypress/e2e/namespaces/execution-environments-edit.js b/cypress/e2e/namespaces/execution-environments-edit.js deleted file mode 100644 index 69140441..00000000 --- a/cypress/e2e/namespaces/execution-environments-edit.js +++ /dev/null @@ -1,85 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -function deleteContainersManual() { - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/execution-environments/repositories/?*`, - ).as('listLoad'); - - cy.visit(`${uiPrefix}containers`); - - cy.wait('@listLoad').then(({ response: { body } }) => { - body.data.forEach((element) => { - cy.get( - `tr[data-cy="ExecutionEnvironmentList-row-${element.name}"] button[aria-label="Actions"]`, - ).click(); - cy.contains('a', 'Delete').click(); - cy.get('input[id=delete_confirm]').click(); - cy.contains('button', 'Delete').click(); - cy.wait('@listLoad', { timeout: 50000 }); - cy.get('.pf-v5-c-alert__action').click(); - }); - }); -} - -function deleteRegistriesManual() { - cy.intercept( - 'GET', - `${apiPrefix}_ui/v1/execution-environments/registries/?*`, - ).as('registries'); - - cy.visit(`${uiPrefix}registries`); - - cy.wait('@registries').then(({ response: { body } }) => { - body.data.forEach((element) => { - cy.get( - `tr[data-cy="ExecutionEnvironmentRegistryList-row-${element.name}"] button[aria-label="Actions"]`, - ).click(); - cy.contains('a', 'Delete').click(); - cy.contains('button', 'Delete').click(); - cy.wait('@registries'); - }); - }); -} - -describe('containers', () => { - const num = (~~(Math.random() * 1000000)).toString(); - - before(() => { - cy.login(); - deleteRegistriesManual(); - deleteContainersManual(); - - cy.addLocalContainer(`localpine${num}`, 'alpine'); - }); - - beforeEach(() => { - cy.login(); - cy.menuGo('Containers > Containers'); - }); - - it('edits a remote container', () => { - cy.contains('a', `remotepine${num}`).click(); - cy.get('.pf-v5-c-button.pf-m-secondary').contains('Edit').click(); - cy.get('#description').type('This is the description.'); - cy.contains('button', 'Save').click(); - cy.wait(10000); - cy.get('[data-cy=description]').should( - 'have.text', - 'This is the description.', - ); - }); - - it('edits a local container', () => { - cy.contains('a', `localpine${num}`).click(); - cy.get('.pf-v5-c-button.pf-m-secondary').contains('Edit').click(); - cy.get('#description').type('This is the description.'); - cy.contains('button', 'Save').click(); - cy.wait(10000); - cy.get('[data-cy=description]').should( - 'have.text', - 'This is the description.', - ); - }); -}); diff --git a/cypress/e2e/namespaces/execution-environments.js b/cypress/e2e/namespaces/execution-environments.js deleted file mode 100644 index bedb3209..00000000 --- a/cypress/e2e/namespaces/execution-environments.js +++ /dev/null @@ -1,39 +0,0 @@ -describe('containers', () => { - const num = (~~(Math.random() * 1000000)).toString(); - - beforeEach(() => { - cy.login(); - cy.menuGo('Containers > Containers'); - }); - - it('checks the EE list view', () => { - cy.contains('a', `remotepine${num}`); - cy.contains('button', 'Add container'); - cy.contains('button', 'Push container images'); - cy.contains('table th', 'Container repository name'); - cy.contains('table th', 'Description'); - cy.contains('table th', 'Created'); - cy.contains('table th', 'Last modified'); - cy.contains('table th', 'Container registry type'); - }); - - it('checks the EE detail view', () => { - cy.contains('a', `remotepine${num}`).click(); - cy.get('[data-cy="title-box"]').should('have.text', `remotepine${num}`); - cy.get('.pf-v5-c-clipboard-copy__text').should( - 'have.text', - `podman pull --tls-verify=false localhost:8002/remotepine${num}`, - ); - }); - - it('adds a Readme', () => { - cy.contains('a', `remotepine${num}`).click(); - cy.get('[data-cy=add-readme]').click(); - cy.get('textarea').type('{del}This is the readme file.'); - cy.get('[data-cy=save-readme]').click(); - cy.get('.markdown-editor').should( - 'have.text', - 'Raw MarkdownThis is the readme file.PreviewThis is the readme file.', - ); - }); -}); diff --git a/cypress/e2e/namespaces/group-list.js b/cypress/e2e/namespaces/group-list.js deleted file mode 100644 index c7c52564..00000000 --- a/cypress/e2e/namespaces/group-list.js +++ /dev/null @@ -1,62 +0,0 @@ -import { range } from 'lodash'; - -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Group list tests for sorting, paging and filtering', () => { - const items = []; - - before(() => { - range(21).forEach((i) => { - const name = 'group_test' + i; - items.push(name); - }); - - items.sort(); - }); - - beforeEach(() => { - cy.login(); - cy.visit(`${uiPrefix}group-list`); - }); - - it('table contains all columns', () => { - cy.get('tr[data-cy="SortTable-headers"] th').contains('Group'); - }); - - it('paging', () => { - cy.get('.pulp-section').contains(items[0]); - - cy.get('.pulp-section').get('[aria-label="Go to next page"]:first').click(); - cy.get('.pulp-section').contains(items[10]); - - cy.get('.pulp-section').get('[aria-label="Go to next page"]:first').click(); - cy.get('.pulp-section').contains(items[20]); - }); - - it('sorting', () => { - cy.get('.pulp-section').get('[data-cy="sort_name"]').click(); - cy.get('.pulp-section tbody tr:first td:first').contains(items[20]); - cy.get('.pulp-section').contains(items[0]).should('not.exist'); - }); - - it('filter', () => { - cy.get('.pulp-section') - .get('[placeholder="Filter by group name"]:first') - .type('group_test0{enter}'); - cy.get('.pulp-section').contains('group_test0'); - cy.get('.pulp-section').contains('group_test1').should('not.exist'); - }); - - it('set page size', () => { - cy.get('.pulp-section') - .get('[data-ouia-component-type="PF5/Pagination"] button:first') - .click(); - cy.get('.pulp-section').contains('20 per page').click(); - - range(20).forEach((i) => { - cy.get('.pulp-section').contains(items[i]); - }); - - cy.get('.pulp-section').contains(items[20]).should('not.exist'); - }); -}); diff --git a/cypress/e2e/namespaces/group-management.js b/cypress/e2e/namespaces/group-management.js deleted file mode 100644 index be8f45f0..00000000 --- a/cypress/e2e/namespaces/group-management.js +++ /dev/null @@ -1,131 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); - -function createGroupManually(name) { - cy.intercept('GET', `${apiPrefix}_ui/v1/groups/?*`).as('loadGroups'); - cy.menuGo('User Access > Groups'); - cy.wait('@loadGroups'); - - cy.contains('Create').click(); - - cy.intercept('POST', `${apiPrefix}_ui/v1/groups/`).as('submitGroup'); - cy.contains('div', 'Name *') - .closest('*:has(input)') - .find('input') - .first() - .type(`${name}{enter}`); - cy.wait('@submitGroup'); - - // Wait for the list to update - cy.contains(name).should('exist'); -} - -function addUserToGroupManually(groupName, username) { - cy.menuGo('User Access > Groups'); - cy.get(`[data-cy="GroupList-row-${groupName}"] a`).click(); - cy.contains('a.pf-v5-c-tabs__link', 'Users').click(); - cy.contains('button', 'Add').click(); - cy.get('.pf-v5-c-select__toggle-typeahead input').type(username); - cy.contains('button', username).click(); - cy.get('.pf-v5-c-content h2').click(); // click modal header to close dropdown - cy.contains('footer > button', 'Add').click({ force: true }); - cy.get(`[data-cy="GroupDetail-users-${username}"]`).should('exist'); -} - -function deleteGroupManually(name) { - cy.menuGo('User Access > Groups'); - cy.intercept('DELETE', `${apiPrefix}_ui/v1/groups/*`).as('deleteGroup'); - cy.intercept('GET', `${apiPrefix}_ui/v1/groups/?*`).as('listGroups'); - cy.get(`[data-cy="GroupList-row-${name}"] [aria-label="Actions"]`).click(); - cy.get('[aria-label=Delete]').click(); - cy.contains('[role=dialog] button', 'Delete').click(); - cy.wait('@deleteGroup').then(({ response }) => { - expect(response.statusCode).to.eq(204); - }); - - // Wait for list reload - cy.wait('@listGroups'); - cy.contains('No groups yet').should('exist'); -} - -function removeUserFromGroupManually(groupName, username) { - cy.menuGo('User Access > Groups'); - cy.get(`[data-cy="GroupList-row-${groupName}"] a`).click(); - cy.contains('a.pf-v5-c-tabs__link', 'Users').click(); - cy.get( - `[data-cy="GroupDetail-users-${username}"] [aria-label="Actions"]`, - ).click(); - cy.containsnear( - `[data-cy="GroupDetail-users-${username}"] [aria-label="Actions"]`, - 'Remove', - ).click(); - cy.contains('button.pf-m-danger', 'Delete').click(); - cy.contains('[data-cy=main-tabs]', username).should('not.exist'); -} - -describe('Pulp Group Management Tests', () => { - beforeEach(() => { - cy.login(); - }); - - it('admin user can create/delete a group', () => { - const name = 'testGroup'; - - createGroupManually(name); - deleteGroupManually(name); - cy.contains('No groups yet').should('exist'); - }); - - it('admin user can add/remove a user to/from a group', () => { - const groupName = 'testGroup'; - const username = 'testUser'; - - cy.createUser(username); - createGroupManually(groupName); - - addUserToGroupManually(groupName, username); - - removeUserFromGroupManually(groupName, username); - }); - - it('admin user can add/remove roles to/from a group', () => { - const groupName = 'testGroup'; - const roleName = 'galaxy.test_role'; - - // add role to group manually - cy.intercept('GET', `${apiPrefix}_ui/v1/groups/*`).as('groups'); - cy.menuGo('User Access > Groups'); - cy.get(`[data-cy="GroupList-row-${groupName}"] a`).click(); - cy.wait('@groups'); - cy.get('[data-cy=add-roles]').click(); - - cy.get('[data-ouia-component-type="PF5/Pagination"] button:first').click(); - - cy.contains('100 per page').click(); - - cy.get(`[data-cy="RoleListTable-CheckboxRow-row-${roleName}"]`) - .find('input') - .click(); - - cy.get('.pf-v5-c-wizard__footer > button').contains('Next').click(); - - cy.contains(roleName); - - cy.intercept('GET', `${apiPrefix}roles/*`).as('roles'); - - cy.get('.pf-v5-c-wizard__footer > button').contains('Add').click(); - - cy.contains( - `Role ${roleName} has been successfully added to ${groupName}.`, - ); - - cy.get(`[data-cy="RoleListTable-ExpandableRow-row-${roleName}"]`); - - cy.get( - `[data-cy="RoleListTable-ExpandableRow-row-${roleName}"] [data-cy="kebab-toggle"]`, - ).click(); - cy.get('.pf-v5-c-dropdown__menu-item').contains('Remove role').click(); - cy.get('[data-cy="delete-button"]').contains('Delete').click(); - - cy.contains('There are currently no roles assigned to this group.'); - }); -}); diff --git a/cypress/e2e/namespaces/group-roles.js b/cypress/e2e/namespaces/group-roles.js deleted file mode 100644 index 4696b4e8..00000000 --- a/cypress/e2e/namespaces/group-roles.js +++ /dev/null @@ -1,157 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); - -describe('Group Roles Tests', () => { - const num = (~~(Math.random() * 1000000)).toString(); - const groupName = `test_group_${num}`; - - const testRole = { - name: `galaxy.test_role_${num}`, - description: 'test role for test group', - permissions: { - 'galaxy.add_group': 'Add group', - 'galaxy.change_group': 'Change group', - 'galaxy.delete_group': 'Delete group', - 'galaxy.view_group': 'View group', - 'galaxy.add_namespace': 'Add namespace', - 'galaxy.delete_namespace': 'Delete namespace', - }, - }; - - const testContainerRole = { - name: `galaxy.test_container_role_${num}`, - description: 'this is test container role', - permissions: { - 'container.namespace_change_containerdistribution': 'Change containers', - 'container.namespace_modify_content_containerpushrepository': - 'Change image tags', - 'container.delete_containerrepository': 'Delete container repository', - }, - }; - - beforeEach(() => { - cy.login(); - }); - - it('should add a new role to group', () => { - cy.intercept('GET', `${apiPrefix}_ui/v1/groups/*`).as('groups'); - cy.menuGo('User Access > Groups'); - cy.get(`[data-cy="GroupList-row-${groupName}"] a`).click(); - cy.wait('@groups'); - cy.get('[data-cy=add-roles]').click(); - - cy.get( - '.pulp-custom-wizard-layout [data-ouia-component-type="PF5/Pagination"] button:first', - ).click(); - cy.contains('100 per page').click(); - - cy.get( - `[data-cy="RoleListTable-CheckboxRow-row-${testRole.name}"] input`, - ).click({ force: true }); - - cy.get('.pf-v5-c-wizard__footer > button').contains('Next').click(); - - cy.contains(testRole.name); - - cy.get('.pf-v5-c-wizard__footer > button').contains('Add').click(); - - cy.menuGo('User Access > Groups'); - cy.get(`[data-cy="GroupList-row-${groupName}"] a`).click(); - cy.get('[data-cy="RoleListTable"]').contains(testRole.name); - cy.get( - `[data-cy="RoleListTable-ExpandableRow-row-${testRole.name}"] .pf-v5-c-table__toggle`, - ).click(); - - cy.contains('1 more').click(); - Object.values(testRole.permissions).forEach((perm) => { - cy.contains(perm); - }); - }); - - it('should test filtering of assigned roles', () => { - cy.menuGo('User Access > Groups'); - cy.get(`[data-cy="GroupList-row-${groupName}"] a`).click(); - - cy.get('[aria-label="role__icontains"]').type(`_${num}{enter}`); - cy.get(`[data-cy="RoleListTable-ExpandableRow-row-${testRole.name}"]`); - - cy.get('[aria-label="role__icontains"]').clear().type('foo bar{enter}'); - cy.get('[data-cy="EmptyState"]').contains('No results found'); - - cy.contains('Clear all filters').click(); - cy.get(`[data-cy="RoleListTable-ExpandableRow-row-${testRole.name}"]`); - }); - - it('should test filtering of roles in "Add roles" wizard', () => { - cy.menuGo('User Access > Groups'); - cy.get(`[data-cy="GroupList-row-${groupName}"] a`).click(); - - cy.get('[data-cy=add-roles]').click(); - - cy.get('[aria-label="name__icontains"]').type(`_${num}{enter}`); - cy.get(`[data-cy="RoleListTable-CheckboxRow-row-${testRole.name}"]`); - cy.get('[aria-label="Add roles"]').contains('Clear all filters').click(); - }); - - it('should correctly select and preview roles', () => { - cy.menuGo('User Access > Groups'); - cy.get(`[data-cy="GroupList-row-${groupName}"] a`).click(); - cy.get('[data-cy=add-roles]').click(); - - cy.get( - '.pulp-custom-wizard-layout [data-ouia-component-type="PF5/Pagination"] button:first', - ).click(); - cy.get('.pulp-custom-wizard-layout').contains('100 per page').click(); - - cy.get( - `[data-cy="RoleListTable"] [data-cy="RoleListTable-CheckboxRow-row-${testRole.name}"] [type="checkbox"]`, - ) - .scrollIntoView() - .check() - .should('be.disabled'); - - cy.get( - `[data-cy="RoleListTable"] [data-cy="RoleListTable-CheckboxRow-row-${testContainerRole.name}"] [type="checkbox"]`, - ) - .uncheck() - .should('not.be.disabled') - .click(); - - cy.get('.pf-v5-c-wizard').contains('Selected roles'); - cy.get(`[data-cy="PulpPermission-${testContainerRole.name}"]`); - - cy.contains('Next').click(); - - cy.get('.pulp-custom-wizard-layout').contains(groupName); - cy.get('.pulp-custom-wizard-layout').contains(testContainerRole.name); - - cy.get('.pf-v5-c-wizard__footer > button') - .contains('Add') - .should('not.be.disabled'); - }); - - it('should be able to remove role from group', () => { - cy.menuGo('User Access > Groups'); - cy.get(`[data-cy="GroupList-row-${groupName}"] a`).click(); - - cy.get( - `[data-cy="RoleListTable-ExpandableRow-row-${testRole.name}"] [data-cy="kebab-toggle"]`, - ).click(); - cy.get('.pf-v5-c-dropdown__menu-item').contains('Remove role').click(); - - cy.get('[data-cy="delete-button"]').contains('Delete').click(); - }); - - it('should not display deleted role in group detail', () => { - cy.menuGo('User Access > Groups'); - cy.get(`[data-cy="GroupList-row-${groupName}"] a`).click(); - cy.get('[data-cy="EmptyState"]') - .contains(testContainerRole.name) - .should('not.exist'); - }); - - it('should show group empty state', () => { - cy.menuGo('User Access > Groups'); - cy.get(`[data-cy="GroupList-row-empty_group"] a`).click(); - cy.contains('There are currently no roles assigned to this group.'); - }); -}); diff --git a/cypress/e2e/namespaces/l10n.js b/cypress/e2e/namespaces/l10n.js deleted file mode 100644 index 0b0464a9..00000000 --- a/cypress/e2e/namespaces/l10n.js +++ /dev/null @@ -1,61 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); - -// Note up to date there is no translation for any string in 'es' and 'nl'. -const languageCheckHelper = (url, selector) => (language, message) => { - cy.visit(url, { - onBeforeLoad(win) { - if (language) { - Object.defineProperty(win.navigator, 'languages', { - value: [language], - }); - } - }, - }); - - cy.get(selector).should('contain.text', message); -}; - -describe('Localization tests with the t`String` format', () => { - const helper = languageCheckHelper(`${uiPrefix}tasks`, 'h1'); - - beforeEach(() => { - cy.login(); - }); - - const translations = { - en: 'Task management', - fr: 'Gestion des tâches', - ja: 'タスク管理', - zh: '任务管理', - }; - - Object.entries(translations).forEach(([language, message]) => { - it(`should display the correct translation in ${language}`, () => { - helper(language, message); - }); - }); -}); - -describe('Localization tests with the format', () => { - const helper = languageCheckHelper( - `${uiPrefix}containers`, - '[data-cy="push-images-button"]', - ); - - beforeEach(() => { - cy.login(); - }); - - const translations = { - en: 'Push container images', - fr: 'Pousser images de conteneurs', - ja: 'コンテナーイメージのプッシュ', - zh: '推容器镜像', - }; - - Object.entries(translations).forEach(([language, message]) => { - it(`should display the correct translation in ${language}`, () => { - helper(language, message); - }); - }); -}); diff --git a/cypress/e2e/namespaces/login.js b/cypress/e2e/namespaces/login.js deleted file mode 100644 index e6a6177e..00000000 --- a/cypress/e2e/namespaces/login.js +++ /dev/null @@ -1,48 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -const manualLogin = (username, password) => { - cy.intercept('POST', `${apiPrefix}_ui/v1/auth/login/`).as('login'); - cy.intercept('GET', `${apiPrefix}_ui/v1/feature-flags/`).as('feature-flags'); - - cy.visit(`${uiPrefix}login`); - cy.get('#pf-login-username-id').type(username); - cy.get('#pf-login-password-id').type(`${password}{enter}`); - - cy.wait('@login'); - cy.wait('@feature-flags'); - - cy.assertTitle('Collections'); -}; - -const manualLogout = () => { - cy.intercept('GET', `${apiPrefix}_ui/v1/feature-flags/`).as('feature-flags'); - - cy.get('[data-cy="user-dropdown"] button').click(); - cy.get('[aria-label="logout"]').click(); - - cy.wait('@feature-flags'); -}; - -describe('Login helpers', () => { - const adminUsername = Cypress.env('username'); - const adminPassword = Cypress.env('password'); - const username = 'nopermission'; - const password = 'n0permissi0n'; - - it('can login manually and logout as admin or different user', () => { - manualLogin(username, password); - cy.contains(username); - manualLogout(); - manualLogin(adminUsername, adminPassword); - cy.contains(adminUsername); - }); - - it('can use api login', () => { - cy.login(); - cy.contains(adminUsername); - - cy.login(username, password); - cy.contains(username); - }); -}); diff --git a/cypress/e2e/namespaces/menu.js b/cypress/e2e/namespaces/menu.js deleted file mode 100644 index 0383030f..00000000 --- a/cypress/e2e/namespaces/menu.js +++ /dev/null @@ -1,54 +0,0 @@ -describe('Pulp Menu Tests', () => { - const username = 'nopermission'; - const password = 'n0permissi0n'; - - const menuItems = [ - 'Collections > Collections', - 'Collections > Namespaces', - 'Collections > Repositories', - 'Collections > Remotes', - 'Collections > API token', - 'Collections > Approval', - 'Containers > Containers', - 'Containers > Remote Registries', - 'Task Management', - 'Signature Keys', - 'User Access > Users', - 'User Access > Groups', - 'User Access > Roles', - ]; - - it('admin user sees complete menu', () => { - cy.login(); - - menuItems.forEach((item) => cy.menuPresent(item)); - }); - - describe('user without permissions', () => { - // one more similar test in view-only - const visibleMenuItems = [ - 'Collections > API token', - 'Collections > Collections', - 'Collections > Namespaces', - 'Collections > Repositories', - 'Containers > Containers', - 'Containers > Remote Registries', - 'Signature Keys', - 'Task Management', - ]; - const missingMenuItems = [ - 'Collections > Approval', - 'Collections > Remotes', - 'User Access > Groups', - 'User Access > Roles', - 'User Access > Users', - ]; - - it('sees limited menu', () => { - cy.login(username, password); - - visibleMenuItems.forEach((item) => cy.menuPresent(item)); - missingMenuItems.forEach((item) => cy.menuMissing(item)); - }); - }); -}); diff --git a/cypress/e2e/namespaces/namespace-delete.js b/cypress/e2e/namespaces/namespace-delete.js deleted file mode 100644 index 85990a44..00000000 --- a/cypress/e2e/namespaces/namespace-delete.js +++ /dev/null @@ -1,51 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Delete a namespace', () => { - beforeEach(() => { - cy.login(); - }); - - it('deletes a namespace', () => { - cy.menuGo('Collections > Namespaces'); - - cy.intercept('GET', `${apiPrefix}_ui/v1/namespaces/?sort=name*`).as( - 'reload', - ); - cy.get(`a[href*="${uiPrefix}namespaces/testns1"]`).click(); - cy.get('[data-cy="ns-kebab-toggle"]').click(); - cy.contains('Delete namespace').click(); - cy.get('input[id=delete_confirm]').click(); - cy.get('button').contains('Delete').click(); - cy.wait('@reload'); - cy.contains('Namespace "testns1" has been successfully deleted.'); - }); - - it('cannot delete a non-empty namespace', () => { - // create namespace - cy.intercept('GET', `${apiPrefix}_ui/v1/namespaces/?sort=name*`).as( - 'reload', - ); - cy.menuGo('Collections > Namespaces'); - cy.wait('@reload'); - - cy.get(`a[href*="${uiPrefix}namespaces/ansible"]`).click(); - - // upload a collection & approve - // attempt deletion - cy.intercept( - 'GET', - `${apiPrefix}_ui/v1/namespaces/?sort=name&offset=0&limit=20`, - ).as('namespaces'); - cy.menuGo('Collections > Namespaces'); - cy.wait('@namespaces'); - cy.contains('ansible') - .parents('.card-wrapper') - .contains('View collections') - .click(); - cy.get('[data-cy=ns-kebab-toggle]').click(); - cy.contains('Delete namespace') - .invoke('attr', 'aria-disabled') - .should('eq', 'true'); - }); -}); diff --git a/cypress/e2e/namespaces/namespace-detail.js b/cypress/e2e/namespaces/namespace-detail.js deleted file mode 100644 index 52aa0ddb..00000000 --- a/cypress/e2e/namespaces/namespace-detail.js +++ /dev/null @@ -1,64 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); -const apiPrefix = Cypress.env('apiPrefix'); - -describe('Namespace detail screen', () => { - beforeEach(() => { - cy.login(); - cy.visit(`${uiPrefix}namespaces/namespace_detail_test`); - }); - - it('should display the collections belonging to the namespace', () => { - cy.get('[data-cy="CollectionListItem"]').should('have.length', 2); - cy.get('[data-cy="CollectionListItem"]').contains('collection1'); - cy.get('[data-cy="CollectionListItem"]').contains('collection2'); - }); - - it('should show deprecation label after button click and page reload', () => { - cy.get( - '[data-cy="CollectionListItem"]:first button[aria-label="Actions"]', - ).click(); - cy.contains('.pulp-section ul a', 'Deprecate').click(); - - // Reload the page - cy.visit(`${uiPrefix}namespaces/namespace_detail_test`); - - cy.get('[data-cy="CollectionListItem"]:first').contains('DEPRECATED'); - }); - - it('should show the correct URL when clicking on the CLI configuration tab', () => { - cy.get('.pf-v5-c-tabs__link').eq(1).click(); - cy.get('.pf-v5-c-clipboard-copy__text').should('contain', apiPrefix); - }); - - it('should show an error when tring to upload a new collecting wiht invalid name', () => { - cy.get('[data-cy="kebab-toggle"] > .pf-v5-c-button').click(); - cy.fixture('collections/invalid-collection-name-1.0.0-bad.tar.gz', 'binary') - .then(Cypress.Blob.binaryStringToBlob) - .then((fileContent) => { - cy.get('input[type="file"]').attachFile({ - fileContent, - fileName: 'invalid-collection-name-1.0.0-bad.tar.gz', - mimeType: 'application/gzip', - }); - }); - cy.get('.file-error-messages').should( - 'contain', - 'does not match this namespace', - ); - - cy.fixture( - 'collections/namespace_detail_test-invalid-1.0.0(1).tar.gz', - 'binary', - ) - .then(Cypress.Blob.binaryStringToBlob) - .then((fileContent) => { - cy.get('input[type="file"]').attachFile({ - fileContent, - fileName: 'namespace_detail_test-invalid-1.0.0(1).tar.gz', - mimeType: 'application/gzip', - }); - }); - cy.get('[data-cy="confirm-upload"]').click(); - cy.get('.file-error-messages').should('contain', 'Invalid filename'); - }); -}); diff --git a/cypress/e2e/namespaces/namespace-edit.js b/cypress/e2e/namespaces/namespace-edit.js deleted file mode 100644 index 34dcb330..00000000 --- a/cypress/e2e/namespaces/namespace-edit.js +++ /dev/null @@ -1,144 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Edit a namespace', () => { - const kebabToggle = () => { - cy.get('[data-cy="ns-kebab-toggle"] button[aria-label="Actions"]').click({ - force: true, - }); - }; - - const saveButton = () => { - return cy.contains('Save'); - }; - - const getLinkTextField = () => { - return cy - .get('div.useful-links > div.link-name input') - .invoke('attr', 'placeholder', 'Link text') - .click(); - }; - - const getUrlField = () => { - return cy.get('div.useful-links div.link-url #url').click(); - }; - - const getEditTab = () => { - return cy - .get( - 'ul.pf-v5-c-tabs__list > li.pf-v5-c-tabs__item > a > span.pf-v5-c-tabs__item-text', - ) - .contains('Edit resources') - .click(); - }; - - const getTextField = () => { - return cy.get( - 'div.pf-v5-c-form__group-control .pf-v5-c-form-control textarea', - ); - }; - - const helperText = (id) => - cy - .get(`#${id}`) - .parents('.pf-v5-c-form__group') - .find('.pf-v5-c-helper-text__item-text'); - - beforeEach(() => { - cy.login(); - cy.menuGo('Collections > Namespaces'); - cy.get(`a[href*="${uiPrefix}namespaces/testns1"]`).click(); - cy.contains('No collections yet'); - kebabToggle(); - cy.contains('Edit namespace').click(); - }); - - it('tests that the name field is disabled from editing', () => { - cy.get('#name').should('be.disabled'); - }); - - it('tests the company name for errors', () => { - cy.get('#company') - .clear() - .type( - 'This name is too long vaðlaheiðarvegavinnuverkfærageymsluskúraútidyralyklakippuhringur', - ); - saveButton().click(); - helperText('company').should( - 'have.text', - 'Ensure this field has no more than 64 characters.', - ); - }); - - it('tests the Logo URL field', () => { - const url = 'https://example.com/'; - cy.get('#avatar_url').clear().type('abcde'); - saveButton().click(); - helperText('avatar_url').contains('Enter a valid URL.'); - cy.get('#avatar_url').clear().type(url); - saveButton().click(); - cy.get('[data-cy="title-box"] img').should('have.attr', 'src', url); - }); - - it('tests the Description field', () => { - cy.get('#description').type(` - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas magna velit, tempor at interdum viverra, egestas quis libero. Aenean arcu magna, sodales ut dictum accumsan, consectetur vitae mi. Maecenas efficitur ipsum a orci condimentum, in lobortis turpis accumsan. Vivamus non libero varius, vulputate nunc vitae, posuere risus. In ut malesuada magna. Cras ac rhoncus mi. Nulla tempus semper interdum. Aliquam scelerisque, purus quis vestibulum finibus, dolor augue dictum erat, id commodo justo quam non metus.`); - saveButton().click(); - helperText('description').should( - 'have.text', - 'Ensure this field has no more than 256 characters.', - ); - cy.get('#description').clear().type('A namespace description'); - saveButton().click(); - cy.get('.pulp-header-bottom').should('contain', 'A namespace description'); - }); - - it('tests the Links field', () => { - getLinkTextField().first().type('Too long ^TrR>dG(F55:5(P:!sdafd#ZWCf2'); - getUrlField().first().type('https://example.com'); - saveButton().click(); - helperText('url').should( - 'contain', - 'Text: Ensure this field has no more than 32 characters.', - ); - getLinkTextField().first().clear(); - cy.contains('.useful-links', 'Name must not be empty.'); - - getLinkTextField().first().type('Link to example website'); - getUrlField().first().clear(); - cy.contains('.useful-links', 'URL must not be empty.'); - - getUrlField().first().type('example.com'); - cy.contains('.useful-links', 'The URL needs to be in'); - - getUrlField().first().clear().type('https://example.com/'); - saveButton().click(); - cy.get('div.link a') - .should('contain', 'Link to example website') - .and('have.attr', 'href', 'https://example.com/'); - }); - - it('removes a link', () => { - cy.get( - 'div.useful-links:first-child > div.link-button > div.link-container svg', - ) - .first() - .click(); - saveButton().click(); - }); - - it('edits namespace resources', () => { - getEditTab(); - getTextField() - .invoke('attr', 'placeholder') - .should( - 'contain', - '## Custom resources\n\nYou can use this page to add any resources which you think might help your users automate all the things.', - ); - getTextField().click().type('Editing the readme file'); - saveButton().click(); - kebabToggle(); - cy.contains('Edit namespace').click(); - getEditTab(); - getTextField().should('contain', 'Editing the readme file'); - }); -}); diff --git a/cypress/e2e/namespaces/namespace-form.js b/cypress/e2e/namespaces/namespace-form.js deleted file mode 100644 index 4c679168..00000000 --- a/cypress/e2e/namespaces/namespace-form.js +++ /dev/null @@ -1,86 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); - -describe('A namespace form', () => { - const getMessage = () => { - return cy.get('.pf-v5-c-form__helper-text'); - }; - const getCreateButton = () => { - return cy.get('.pf-v5-c-modal-box__footer .pf-m-primary'); - }; - const getInputBox = () => { - return cy.get('input[name="name"]'); - }; - const clearInput = () => { - return getInputBox().clear(); - }; - const createNamespace = () => { - return; - }; - - beforeEach(() => { - cy.login(); - createNamespace(); - cy.menuGo('Collections > Namespaces'); - cy.contains('button', 'Create').click(); - cy.contains('Create a new namespace'); - }); - - it('should give message if input has no characters', () => { - // error is shown only when start typing and then left empty - getInputBox().type('A{backspace}'); - getMessage().should('have.text', 'Please, provide the namespace name'); - getCreateButton().should('be.disabled'); - }); - - it('should give message if input is empty', () => { - getInputBox().type(' '); - getMessage().should( - 'have.text', - 'Name can only contain letters and numbers', - ); - getCreateButton().should('be.disabled'); - clearInput(); - }); - - it('should give message if input has incorrect characters', () => { - getInputBox().type('!/^[a-zA-Z0-9_]+$/.'); - getMessage().should( - 'have.text', - 'Name can only contain letters and numbers', - ); - getCreateButton().should('be.disabled'); - clearInput(); - }); - - it('should give message if input is shorter than 3 characters', () => { - getInputBox().type('na'); - getMessage().should('have.text', 'Name must be longer than 2 characters'); - getCreateButton().should('be.disabled'); - clearInput(); - }); - - it('should give message if input begins with underscore', () => { - getInputBox().type('_namespace'); - getMessage().should('have.text', "Name cannot begin with '_'"); - getCreateButton().should('be.disabled'); - clearInput(); - }); - - it('should give message if name already exists', () => { - getInputBox().type('testns1'); - getCreateButton().click(); - getCreateButton().should('be.disabled'); - getMessage().should( - 'have.text', - 'A namespace named testns1 already exists.', - ); - clearInput(); - }); - - it('creates a new namespace with no error messages', () => { - const id = parseInt(Math.random() * 1000000); - getInputBox().type(`testns_${id}`); - getCreateButton().click(); - cy.url().should('match', new RegExp(`${uiPrefix}namespaces/testns_`)); - }); -}); diff --git a/cypress/e2e/namespaces/namespace-list.js b/cypress/e2e/namespaces/namespace-list.js deleted file mode 100644 index 92193f4f..00000000 --- a/cypress/e2e/namespaces/namespace-list.js +++ /dev/null @@ -1,16 +0,0 @@ -describe('Namespaces Page Tests', () => { - it('can navigate to admin public namespace list', () => { - cy.login(); - cy.menuGo('Collections > Namespaces'); - cy.contains('testns2').should('exist'); - cy.contains('testns1').should('exist'); - }); - - it('can navigate to user public namespace list', () => { - cy.login('testUser2', 'p@ssword1'); - cy.menuGo('Collections > Namespaces'); - - cy.contains('testns2').should('exist'); - cy.contains('testns1').should('exist'); - }); -}); diff --git a/cypress/e2e/namespaces/profile.js b/cypress/e2e/namespaces/profile.js deleted file mode 100644 index ee17d201..00000000 --- a/cypress/e2e/namespaces/profile.js +++ /dev/null @@ -1,141 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); - -const helperText = (id) => - cy - .get(`#${id}`) - .parents('.pf-v5-c-form__group') - .find('.pf-v5-c-helper-text__item-text'); - -describe('My Profile Tests', () => { - const username = 'nopermission'; - const password = 'n0permissi0n'; - - beforeEach(() => { - cy.login(); - cy.get('[data-cy="user-dropdown"] button').click(); - cy.contains('a', 'My profile').click(); - cy.contains('button', 'Edit').click(); - }); - - it('only has input fields for name, email, username, password and pass confirmation', () => { - const inputs = [ - 'first_name', - 'last_name', - 'email', - 'username', - 'password', - 'password-confirm', - ]; - cy.get('.pulp-section').within(() => { - // restricted to text input types because there's a checkbox now for the - // 'super user' option, but it's disabled. - cy.get('input[type="text"]').each(($el) => { - expect(inputs).to.include($el.attr('id')); - }); - }); - }); - - it('superuser cannot change its superuser rights', () => { - cy.get('.pf-v5-c-switch__input').should('be.disabled'); - }); - - it('user cannot set superusers rights', () => { - cy.login(username, password); - - cy.get('[data-cy="user-dropdown"] button').click(); - cy.contains('a', 'My profile').click(); - cy.contains('button', 'Edit').click(); - - cy.get('.pf-v5-c-switch__input').should('be.disabled'); - }); - - it('email must be email', () => { - cy.login(username, password); - - cy.get('[data-cy="user-dropdown"] button').click(); - cy.get('a').contains('My profile').click(); - cy.get('button:contains("Edit")').click(); - - cy.get('#email').clear().type('test{enter}'); - helperText('email').should('contain', 'Enter a valid email address.'); - - cy.get('#email').type('@example'); - helperText('email').should('contain', 'Enter a valid email address.'); - - cy.get('#email').type('.com{enter}'); - - cy.get('.pf-v5-c-alert.pf-m-success').should('be.visible'); - }); - - it('password validations', () => { - cy.login(username, password); - - cy.get('[data-cy="user-dropdown"] button').click(); - cy.get('a').contains('My profile').click(); - cy.get('button:contains("Edit")').click(); - - cy.get('#password').clear().type('12345'); - cy.get('#password-confirm').clear().type('12345'); - cy.contains('Save').click(); - helperText('password').contains('This password is entirely numeric.'); - - cy.get('#password').clear().type('pwd12345'); - cy.get('#password-confirm').clear().type('pwd12345'); - cy.contains('Save').click(); - helperText('password').contains( - 'This password is too short. It must contain at least 9 characters.', - ); - - cy.get('#password-confirm').clear().type('pwd123456'); - helperText('password-confirm').should('contain', 'Passwords do not match'); - - cy.get('#password').clear().type(password); - cy.get('#password-confirm').clear().type(password); - helperText('password-confirm').should('be.empty'); - }); - - it('groups input is readonly', () => { - cy.get('[data-cy="UserForm-readonly-groups"]').should('not.exist'); - }); - - it('user can save form', () => { - cy.intercept('PUT', `${apiPrefix}_ui/v1/me/`).as('saveForm'); - - cy.contains('Save').click(); - cy.get('.pf-v5-c-alert.pf-m-success').contains( - 'Saved changes to user "admin".', - ); - - cy.wait('@saveForm').its('response.statusCode').should('eq', 200); - - cy.get('.pf-v5-c-alert.pf-m-success').contains( - 'Saved changes to user "admin".', - ); - }); - - it('user can cancel form', () => { - cy.get('#username').clear().type('administrator'); - cy.get('#first_name').clear().type('First Name'); - cy.get('#last_name').clear().type('Last Name'); - cy.get('#email').clear().type('administrator@example.com'); - - cy.get('.pf-v5-c-button').contains('Cancel').click(); - - cy.get('[data-cy="DataForm-field-username"]').should( - 'not.contain', - 'administrator', - ); - cy.get('[data-cy="DataForm-field-first_name"]').should( - 'not.contain', - 'First Name', - ); - cy.get('[data-cy="DataForm-field-last_name"]').should( - 'not.contain', - 'Last Name', - ); - cy.get('[data-cy="DataForm-field-email"]').should( - 'not.contain', - 'administrator@example.com', - ); - }); -}); diff --git a/cypress/e2e/namespaces/rbac-access.js b/cypress/e2e/namespaces/rbac-access.js deleted file mode 100644 index 08974197..00000000 --- a/cypress/e2e/namespaces/rbac-access.js +++ /dev/null @@ -1,168 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Namespace Access tab', () => { - const num = (~~(Math.random() * 1000000)).toString(); - - beforeEach(() => { - cy.login(); - cy.visit(`${uiPrefix}namespaces/rbac_access_${num}`); - cy.get('.pf-v5-c-tabs__item-text').contains('Access').click(); - }); - - it('add and remove group and roles', () => { - testAccessTab({ - num, - permission: 'change_namespace', - permissionGroup: 'Galaxy', - permissionLabel: 'Change namespace', - role: 'galaxy.collection_publisher', - roleFilter: 'publish', - }); - }); -}); - -describe('Container Access tab', () => { - const num = (~~(Math.random() * 1000000)).toString(); - - beforeEach(() => { - cy.login(); - cy.visit(`${uiPrefix}containers/rbac_access_${num}`); - cy.get('.pf-v5-c-tabs__item-text').contains('Access').click(); - }); - - it('add and remove group and roles', () => { - testAccessTab({ - num, - permission: 'change_containernamespace', - permissionGroup: 'Container', - permissionLabel: 'Change container namespace permissions', - role: 'galaxy.execution_environment_publisher', - roleFilter: 'publish', - }); - }); -}); - -function testAccessTab({ - num, - permission, - permissionGroup, - permissionLabel, - role, - roleFilter, -}) { - // new thing, expect no owners - cy.get('.pf-v5-c-empty-state'); - cy.get('button').contains('Select a group').click(); - - // group role modal - // find partner-engineers, select, check indicator, next - cy.get('[data-cy=compound_filter] input[aria-label=name__icontains]').type( - 'access{enter}', - ); - cy.get( - '[data-cy="GroupListTable-CheckboxRow-row-access_group"] input[type=radio]', - ).click(); - - cy.get('strong').contains('Selected group'); - cy.get('.pulp-permission').contains('access_group'); - - cy.get('footer button').contains('Next').click(); - - // find collection_publisher, select, check indicator, next - cy.get('[data-cy=compound_filter] input[aria-label=name__icontains]').type( - `${roleFilter}{enter}`, - ); - cy.get( - `[data-cy="RoleListTable-CheckboxRow-row-${role}"] input[type=checkbox]`, - ).click(); - - cy.get('strong').contains('Selected roles'); - cy.get('.pulp-permission').contains(role); - - cy.get('footer button').contains('Next').click(); - - // see preview, add - cy.get('strong').contains('access_group'); - cy.get('strong').contains(role); - - cy.get('.pulp-permission strong').contains(permissionGroup); - cy.get('.pulp-permission').contains(permission); - - cy.get('footer button').contains('Add').click(); - cy.get('.pf-v5-c-alert__title') - .contains( - `Group "access_group" has been successfully added to "rbac_access_${num}".`, - ) - .parent('.pf-v5-c-alert') - .find('button') - .click(); - cy.get('tr[data-cy="AccessTab-row-group-access_group"]'); - - // group list view, try modal, open group - cy.get('button').contains('Select a group').click(); - cy.get('.pf-v5-c-wizard__footer-cancel').click(); - - cy.get('tr[data-cy="AccessTab-row-group-access_group"] a').click(); - - // role list view, use modal - cy.get(`[data-cy="RoleListTable-ExpandableRow-row-${role}"]`); - cy.get('button').contains('Add roles').click(); - cy.get('.pf-v5-c-table__check input[type=checkbox]') - .not('[disabled]') - .first() - .click(); - cy.get('footer button').contains('Next').click(); - cy.get('footer button').contains('Add').click(); - cy.get('.pf-v5-c-alert__title') - .contains( - `Group "access_group" roles successfully updated in "rbac_access_${num}".`, - ) - .parent('.pf-v5-c-alert') - .find('button') - .click(); - - // role list view, expand - cy.get('tbody[role=rowgroup]').should('have.length', 2); - cy.get( - `[data-cy="RoleListTable-ExpandableRow-row-${role}"] .pf-v5-c-table__toggle button`, - ).click(); - cy.contains('.pf-v5-c-label', permissionLabel, { timeout: 10000 }); - - // role list view, remove - cy.get( - `[data-cy="RoleListTable-ExpandableRow-row-${role}"] [data-cy=kebab-toggle] button`, - ).click(); - cy.get('.pf-v5-c-dropdown__menu-item').contains('Remove role').click(); - cy.get('.pf-v5-c-modal-box__body b').contains('access_group'); - cy.get('.pf-v5-c-modal-box__body b').contains(role); - cy.get('.pf-v5-c-modal-box__body b').contains(`rbac_access_${num}`); - cy.get('[data-cy=delete-button]').click(); - cy.get('.pf-v5-c-alert__title') - .contains( - `Group "access_group" roles successfully updated in "rbac_access_${num}".`, - ) - .parent('.pf-v5-c-alert') - .find('button') - .click(); - - // breadcrumb back to group list - cy.contains('.pf-v5-c-tabs__item', 'Access').click(); - cy.contains('button', 'Select a group'); - - // list view, delete, see empty - cy.get( - 'tr[data-cy="AccessTab-row-group-access_group"] [data-cy=kebab-toggle] button', - ).click(); - cy.get('.pf-v5-c-dropdown__menu-item').contains('Remove group').click(); - cy.get('.pf-v5-c-modal-box__body b').contains('access_group'); - cy.get('.pf-v5-c-modal-box__body b').contains(`rbac_access_${num}`); - cy.get('[data-cy=delete-button]').click(); - cy.get('.pf-v5-c-alert__title') - .contains( - `Group "access_group" has been successfully removed from "rbac_access_${num}".`, - ) - .parent('.pf-v5-c-alert') - .find('button') - .click(); - cy.get('.pf-v5-c-empty-state'); -} diff --git a/cypress/e2e/namespaces/rbac-create.js b/cypress/e2e/namespaces/rbac-create.js deleted file mode 100644 index eb3572af..00000000 --- a/cypress/e2e/namespaces/rbac-create.js +++ /dev/null @@ -1,86 +0,0 @@ -const helperText = (id) => - cy - .get(`#${id}`) - .parents('.pf-v5-c-form__group') - .find('.pf-v5-c-helper-text__item-text'); - -describe('add and delete roles', () => { - const num = (~~(Math.random() * 1000000)).toString(); - before(() => { - cy.login(); - cy.menuGo('User Access > Roles'); - }); - - it('adds a new role', () => { - cy.contains('Add roles').click(); - - // checks role name input - - cy.get('#role_name').type('a'); - helperText('role_name').should( - 'have.text', - 'This field must be longer than 2 characters', - ); - cy.contains('Save').should('be.disabled'); - - cy.get('#role_name').clear().type('['); - helperText('role_name').should( - 'have.text', - 'This field can only contain letters and numbers', - ); - cy.contains('Save').should('be.disabled'); - - cy.get('#role_name').clear().type('test'); - cy.get('#role_name').clear(); - helperText('role_name').should('have.text', 'This field may not be blank.'); - cy.contains('Save').should('be.disabled'); - - cy.get('#role_name').clear().type(`galaxy.test${num}`); - cy.contains('Save').should('be.enabled'); - - // checks role description input - - cy.get('#role_description').type('a'); - helperText('role_description').should( - 'have.text', - 'This field must be longer than 2 characters', - ); - cy.contains('Save').should('be.disabled'); - - cy.get('#role_description').clear(); - helperText('role_description').should( - 'have.text', - 'This field may not be blank.', - ); - cy.contains('Save').should('be.disabled'); - - cy.get('#role_description').clear().type('test description'); - cy.contains('Save').should('be.enabled'); - - // add permissions - - cy.contains('Collection Namespaces') - .parent() - .find('input', 'Select Permissions') - .click(); - cy.get('ul[role="listbox"] > li:first').click(); - - cy.contains('Save').click(); - - // check list view, use filter - - cy.get('[data-cy=compound_filter] input').type('test{enter}'); - - cy.get('tbody').contains(`galaxy.test${num}`); - cy.get('[aria-label="Details"]:first').click(); - cy.contains('Add namespace'); - - // delete role - - cy.get('[aria-label="Actions"]:first').click(); - cy.contains('Delete').click(); - cy.get('button').contains('Delete').click(); - cy.get('.pf-v5-c-alert__action').click(); - cy.contains(`galaxy.test${num}`).should('not.exist'); - }); -}); diff --git a/cypress/e2e/namespaces/rbac-edit.js b/cypress/e2e/namespaces/rbac-edit.js deleted file mode 100644 index 3e0c2bf0..00000000 --- a/cypress/e2e/namespaces/rbac-edit.js +++ /dev/null @@ -1,72 +0,0 @@ -describe('edits a role', () => { - const num = (~~(Math.random() * 1000000)).toString(); - - beforeEach(() => { - cy.login(); - cy.menuGo('User Access > Roles'); - }); - - it('edits a role', () => { - // create role - - cy.contains('Add roles').click(); - cy.get('input[id="role_name"]').type(`galaxy.test${num}`); - cy.get('input[id="role_description"]').type('test description'); - - cy.contains('Collection Namespaces') - .parent() - .find('input', 'Select Permissions') - .click(); - cy.get('ul[role="listbox"] > li:first').click(); // add permission 'Add namespace' - cy.contains('Save').click(); - - // edit role - first filter by editable and name fragment - - cy.get('[data-cy=compound_filter] > div:nth-child(1) > button').click(); - cy.get('[data-cy=compound_filter] [role=menuitem]') - .contains('Editable') - .click(); - cy.get('[data-cy=compound_filter] > div:nth-child(2) > button').click(); - cy.get('[data-cy=compound_filter] [role=menuitem]') - .contains('Editable') - .click(); - - cy.get('[data-cy=compound_filter] > div:nth-child(1) > button').click(); - cy.get('[data-cy=compound_filter] [role=menuitem]') - .contains('Role name') - .click(); - cy.get( - '[data-cy=compound_filter] input[aria-label="name__icontains"]', - ).type(`test${num}{enter}`); - - cy.get('[aria-label="Actions"]:first').click(); - cy.get('[role=menuitem]').contains('Edit').click(); - - cy.get('input[id="role_name"]').should('be.disabled'); - cy.get('input[id="role_description"]').clear().type('new description'); - - cy.contains('Collection Namespaces') - .parent() - .find('input', 'Select Permissions') - .click(); - cy.get('ul[role="listbox"] > li:first').click(); // add permission 'Change namespace' - cy.contains('Save').click(); - - // check list view - - cy.get( - '[data-cy=compound_filter] input[aria-label="name__icontains"]', - ).type(`test${num}{enter}`); - - cy.get('tbody > tr > td').eq(2).contains('new description'); - cy.get('[aria-label="Details"]:first').click(); - cy.contains('Add namespace'); - cy.contains('Change namespace'); - - // cleanup - delete role - - cy.get('[aria-label="Actions"]:first').click(); - cy.contains('Delete').click(); - cy.get('button').contains('Delete').click(); - }); -}); diff --git a/cypress/e2e/namespaces/rbac-list.js b/cypress/e2e/namespaces/rbac-list.js deleted file mode 100644 index 1927c806..00000000 --- a/cypress/e2e/namespaces/rbac-list.js +++ /dev/null @@ -1,19 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); - -describe('RBAC table contains correct headers and filter', () => { - before(() => { - cy.login(); - cy.visit(`${uiPrefix}roles`); - }); - - it('table contains all columns and filter', () => { - cy.login(); - cy.visit(`${uiPrefix}roles`); - cy.contains('Roles'); - - // ensure proper headers - [('Role name', 'Description', 'Created', 'Editable')].forEach((item) => { - cy.get('tr[data-cy="SortTable-headers"] th').contains(item); - }); - }); -}); diff --git a/cypress/e2e/namespaces/rbac.js b/cypress/e2e/namespaces/rbac.js deleted file mode 100644 index b657142a..00000000 --- a/cypress/e2e/namespaces/rbac.js +++ /dev/null @@ -1,240 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); - -const username = 'testUser'; -const userPassword = 'I am a complicated passw0rd'; - -describe('RBAC test for user without permissions', () => { - beforeEach(() => { - cy.login(username, userPassword); - }); - - it("shouldn't display create, edit and delete buttons in namespace when user doesn't have permission", () => { - cy.visit(`${uiPrefix}namespaces`); - - // cannot Add namespace - cy.contains('Create').should('not.exist'); - - cy.visit(`${uiPrefix}namespaces/testspace`); - - // cannot Change namespace and Delete namespace - cy.get('[data-cy=kebab-toggle]').should('not.exist'); - - // cannot Upload to namespace - cy.contains('Upload collection').should('not.exist'); - }); - - it("shouldn't let delete collection and modify ansible repo content when user doesn't have permission", () => { - cy.visit(`${uiPrefix}repo/published/testspace/testcollection`); - - // cannot Delete collection - cy.get('[data-cy="kebab-toggle"]').should('not.exist'); - }); - - it("shouldn't let view, add, change and delete users when user doesn't have permission", () => { - // cannot View user - cy.menuMissing('User Access > Users'); - cy.visit(`${uiPrefix}users`); - cy.contains('You do not have access to Pulp UI'); - - // cannot Add user - cy.contains('Create').should('not.exist'); - cy.visit(`${uiPrefix}users/create`); - cy.contains('You do not have access to Pulp UI'); - - // cannot Change and Delete user - cy.visit(`${uiPrefix}users`); - cy.get('[data-cy="UserList-row-testUser"] [data-cy=kebab-toggle]').should( - 'not.exist', - ); - }); - - it("shouldn't let view, add, change and delete groups when user doesn't have permission", () => { - // cannot View group - cy.menuMissing('User Access > Groups'); - cy.visit(`${uiPrefix}group-list`); - cy.contains('You do not have access to Pulp UI'); - - // cannot Add group - cy.contains('Create').should('not.exist'); - - // cannot Change and Delete group - cy.get('[data-cy="GroupList-row-testgroup"]').should('not.exist'); - }); - - it("shouldn't let create, edit or delete container when user doesn't have permission", () => { - cy.visit(`${uiPrefix}containers`); - - // cannot Create new containers - cy.contains('Add container').should('not.exist'); - - // cannot Change and Delete container - cy.get( - '[data-cy="ExecutionEnvironmentList-row-testcontainer"] [data-cy="kebab-toggle"]', - ).click(); - cy.contains('Edit').should('not.exist'); - cy.contains('Delete').should('not.exist'); - - cy.visit(`${uiPrefix}containers/testcontainer`); - cy.contains('Edit').should('not.exist'); - cy.get('[aria-label="Actions"]').click(); - cy.contains('Delete').should('not.exist'); - - // temporary solution (button should not be visible, if user has no permissions to sync it) - cy.contains('Sync from registry').should('not.exist'); - }); - - it("shouldn't let add, delete and sync remote registries when user doesn't have permission", () => { - // can Add remote registry - // in here we hide the button (correct), but in containers we dont (wrong) - cy.visit(`${uiPrefix}registries`); - cy.contains('Add remote registry').should('not.exist'); - - // can Change and Delete remote registry - cy.get( - '[data-cy="ExecutionEnvironmentRegistryList-row-docker"] [data-cy="kebab-toggle"]', - ).click(); - cy.contains('Edit').should('not.exist'); - cy.contains('Delete').should('not.exist'); - - // cannot sync remote registry - cy.contains('Sync from registry').should('not.exist'); - }); - - it("should let view task when user doesn't have permission", () => { - cy.visit(`${uiPrefix}tasks`); - cy.get('[aria-label="Task list"] tr td a').first().click(); - cy.contains('Task detail'); - }); -}); - -describe('RBAC test for user with permissions', () => { - before(() => { - cy.login(); - - cy.addRemoteContainer({ - name: `testcontainer`, - upstream_name: 'library/alpine', - registry: `docker`, - include_tags: 'latest', - }); - }); - - it('should display create, edit and delete buttons in namespace when user has permissions', () => { - cy.login(username, userPassword); - - cy.visit(`${uiPrefix}namespaces`); - - // can Add namespace - cy.contains('Create').should('exist'); - cy.visit(`${uiPrefix}namespaces/testspace2`); - cy.get('[data-cy="ns-kebab-toggle"]').should('exist').click(); - cy.contains('Edit namespace'); - cy.contains('Delete namespace'); - - // can Upload to namespace - cy.contains('Upload collection').should('exist'); - }); - - it('should let delete collection and modify ansible repo content when user has permissions', () => { - cy.login(username, userPassword); - - cy.visit(`${uiPrefix}repo/published/testspace2/testcollection2`); - cy.contains('Go to documentation'); - - // can Delete collection - cy.openHeaderKebab(); - cy.contains('Delete collection from system'); - }); - - it('should let view, add, change and delete users when user has permissions', () => { - cy.login(username, userPassword); - - // can View user - cy.menuPresent('User Access > Users'); - cy.visit(`${uiPrefix}users`); - cy.contains('Users'); - - // can Add user - cy.contains('Create'); - cy.visit(`${uiPrefix}users/create`); - cy.contains('Create new user'); - - // can Change and Delete user - cy.visit(`${uiPrefix}users`); - cy.get( - '[data-cy="UserList-row-testUser"] [data-cy=kebab-toggle] > .pf-v5-c-dropdown', - ).click(); - cy.contains('Edit').should('exist'); - cy.contains('Delete').should('exist'); - }); - - it('should let view, add, change and delete groups when user has permissions', () => { - cy.login(username, userPassword); - - // can View group - cy.menuPresent('User Access > Groups'); - cy.visit(`${uiPrefix}group-list`); - cy.contains('Groups'); - - // can Add group - cy.contains('Create').should('exist'); - - // can Change and Delete group - cy.get( - '[data-cy="GroupList-row-testgroup"] [data-cy=kebab-toggle] > .pf-v5-c-dropdown', - ).click(); - cy.contains('Delete').should('exist'); - }); - - it('should let create, edit or delete container when user has permission', () => { - cy.login(username, userPassword); - - cy.visit(`${uiPrefix}containers`); - - // can Create new containers - cy.contains('Add container').should('exist'); - - // can Change and Delete container - cy.get( - '[data-cy="ExecutionEnvironmentList-row-testcontainer"] [data-cy="kebab-toggle"]', - ).click(); - cy.contains('Edit').should('exist'); - cy.contains('Delete').should('exist'); - - cy.visit(`${uiPrefix}containers/testcontainer`); - cy.contains('Edit').should('exist'); - cy.get('[aria-label="Actions"]').click(); - cy.contains('Delete').should('exist'); - cy.contains('Sync from registry').click(); - cy.get('[data-cy="AlertList"] .pf-v5-c-alert__title').contains( - 'Sync started for remote registry "testcontainer".', - ); - }); - - it('should let add, delete and sync remote registries when user has permission', () => { - cy.login(username, userPassword); - - // can Add remote registry - cy.visit(`${uiPrefix}registries`); - cy.contains('Add remote registry').should('exist'); - - // can Change and Delete remote registry - cy.get('[data-cy="kebab-toggle"]').click(); - cy.contains('Edit'); - cy.contains('Delete'); - - // can sync remote registry - cy.contains('Sync from registry').click(); - cy.get('[data-cy="AlertList"] .pf-v5-c-alert__title').contains( - 'Sync started for remote registry "docker".', - ); - }); - - it('should let view task when user has permission', () => { - cy.login(username, userPassword); - - cy.visit(`${uiPrefix}tasks`); - cy.get('[aria-label="Task list"] tr td a').first().click(); - cy.contains('Task detail'); - }); -}); diff --git a/cypress/e2e/namespaces/task-list.js b/cypress/e2e/namespaces/task-list.js deleted file mode 100644 index c93f4dd9..00000000 --- a/cypress/e2e/namespaces/task-list.js +++ /dev/null @@ -1,33 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Task table contains correct headers and filter', () => { - before(() => { - cy.login(); - cy.visit(`${uiPrefix}ansible/repositories`); - - cy.contains('Repositories'); - - cy.intercept('POST', `${apiPrefix}content/certified/v3/sync/`).as('sync'); - - cy.intercept('GET', `${apiPrefix}_ui/v1/remotes/?*`).as('remotes'); - - cy.get('[aria-label="Actions"]').eq(1).click(); - cy.get('tr').eq(2).contains('Sync').click(); - cy.get('.pf-v5-c-modal-box__footer .pf-m-primary').contains('Sync').click(); - - cy.get('.pf-v5-c-alert.pf-m-info'); - }); - - it('table contains all columns and filter', () => { - cy.login(); - cy.visit(`${uiPrefix}tasks`); - cy.contains('Task Management'); - cy.get('[aria-label="name__contains"]'); - ['Task name', 'Created on', 'Started at', 'Finished at', 'Status'].forEach( - (item) => { - cy.get('tr[data-cy="SortTable-headers"] th').contains(item); - }, - ); - }); -}); diff --git a/cypress/e2e/namespaces/task-management-detail.js b/cypress/e2e/namespaces/task-management-detail.js deleted file mode 100644 index 15971802..00000000 --- a/cypress/e2e/namespaces/task-management-detail.js +++ /dev/null @@ -1,44 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Task detail', () => { - before(() => { - cy.login(); - cy.visit(`${uiPrefix}ansible/repositories`); - - cy.contains('Repositories'); - - cy.intercept('POST', `${apiPrefix}content/certified/v3/sync/`).as('sync'); - - cy.intercept('GET', `${apiPrefix}_ui/v1/remotes/?*`).as('remotes'); - - cy.get('[aria-label="Actions"]').eq(1).click(); - cy.get('tr').eq(2).contains('Sync').click(); - cy.get('.pf-v5-c-modal-box__footer .pf-m-primary').contains('Sync').click(); - - cy.get('.pf-v5-c-alert.pf-m-info'); - }); - - it('contains correct headers and field names', () => { - cy.login(); - cy.visit(`${uiPrefix}tasks`); - cy.contains('pulp_ansible.app.tasks.collections.sync').click(); - - cy.contains('h1', 'Collections sync'); - cy.contains('.card-area h2', 'Task detail'); - cy.contains('.card-area h2', 'Task groups'); - cy.contains('.card-area h2', 'Reserve resources'); - - // rest of the content in containers - [ - 'Task name', - 'Created on', - 'Finished at', - 'Task group', - 'Parent task', - 'Child task', - ].forEach((item) => { - cy.contains('.card-area', item); - }); - }); -}); diff --git a/cypress/e2e/namespaces/task-status.js b/cypress/e2e/namespaces/task-status.js deleted file mode 100644 index 6ab64be6..00000000 --- a/cypress/e2e/namespaces/task-status.js +++ /dev/null @@ -1,54 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -describe('test status filter label on list view', () => { - before(() => { - cy.login(); - cy.visit(`${uiPrefix}tasks`); - cy.intercept('GET', `${apiPrefix}tasks/?*`).as('tasks'); - - cy.wait('@tasks'); - }); - - it('shows nicename status filter label', () => { - // completed - cy.get( - '.pf-v5-c-input-group > .pf-v5-c-dropdown > .pf-v5-c-dropdown__toggle', - ).click(); - - cy.get('li').contains('Status').click(); - cy.get('.pf-v5-c-input-group').children().eq(1).click(); - cy.get('li > a').contains('Completed').click(); - cy.get('.pf-v5-c-chip-group__list').contains('completed'); - - // failed - cy.get( - '.pf-v5-c-input-group > .pf-v5-c-dropdown > .pf-v5-c-dropdown__toggle', - ).click(); - - cy.get('li').contains('Status').click(); - cy.get('.pf-v5-c-input-group').children().eq(1).click(); - cy.get('li > a').contains('Failed').click(); - cy.get('.pf-v5-c-chip-group__list').contains('failed'); - - // running - cy.get( - '.pf-v5-c-input-group > .pf-v5-c-dropdown > .pf-v5-c-dropdown__toggle', - ).click(); - - cy.get('li').contains('Status').click(); - cy.get('.pf-v5-c-input-group').children().eq(1).click(); - cy.get('li > a').contains('Running').click(); - cy.get('.pf-v5-c-chip-group__list').contains('running'); - - // waiting - cy.get( - '.pf-v5-c-input-group > .pf-v5-c-dropdown > .pf-v5-c-dropdown__toggle', - ).click(); - - cy.get('li').contains('Status').click(); - cy.get('.pf-v5-c-input-group').children().eq(1).click(); - cy.get('li > a').contains('Waiting').click(); - cy.get('.pf-v5-c-chip-group__list').contains('waiting'); - }); -}); diff --git a/cypress/e2e/namespaces/user-dashboard.js b/cypress/e2e/namespaces/user-dashboard.js deleted file mode 100644 index f03c6d8e..00000000 --- a/cypress/e2e/namespaces/user-dashboard.js +++ /dev/null @@ -1,14 +0,0 @@ -describe('Pulp User Management Tests', () => { - describe('prevents super-user and self deletion', () => { - it("the super-user can't delete themselves", () => { - cy.login(); - cy.menuGo('User Access > Users'); - - const actionsSelector = `[data-cy="UserList-row-admin"] [aria-label="Actions"]`; - cy.get(actionsSelector).click(); - cy.containsnear(actionsSelector, 'Delete').click(); - cy.get('button').contains('Delete').should('be.disabled'); - cy.get('button').contains('Cancel').click(); - }); - }); -}); diff --git a/cypress/e2e/namespaces/user-detail.js b/cypress/e2e/namespaces/user-detail.js deleted file mode 100644 index 7585111b..00000000 --- a/cypress/e2e/namespaces/user-detail.js +++ /dev/null @@ -1,66 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -describe('user detail tests all fields, editing, and deleting', () => { - const num = (~~(Math.random() * 1000000)).toString(); - - const selectInput = (id) => cy.get(`input[id=${id}]`).click().clear(); - - beforeEach(() => { - cy.login(); - }); - - it('checks all fields', () => { - cy.visit(`${uiPrefix}users`); - cy.contains('testUser').click(); - cy.contains('Edit').click(); - selectInput('first_name').type('first_name'); - selectInput('last_name').type('last_name'); - selectInput('email').type('example@example.com'); - cy.get('button[type=submit]').click(); - - cy.visit(`${uiPrefix}users`); - cy.intercept('GET', `${apiPrefix}_ui/v1/users/*/`).as('testUser'); - cy.contains('testUser').click(); - cy.wait('@testUser'); - - cy.get('[data-cy="DataForm-field-username"]').contains('testUser'); - cy.get('[data-cy="DataForm-field-first_name"]').contains('first_name'); - cy.get('[data-cy="DataForm-field-last_name"]').contains('last_name'); - cy.get('[data-cy="DataForm-field-email"]').contains('example@example.com'); - cy.get('[data-cy="UserForm-readonly-groups"]').contains(`alphaGroup${num}`); - }); - - it('edits user', () => { - cy.visit(`${uiPrefix}users`); - cy.contains('testUser').click(); - - // edits some fields - cy.contains('Edit').click(); - selectInput('first_name').type('new_first_name'); - selectInput('last_name').type('new_last_name'); - selectInput('email').type('new_example@example.com'); - cy.get('button[type=submit]').click(); - cy.reload(); - - // checks those fields - cy.visit(`${uiPrefix}users`); - cy.intercept('GET', `${apiPrefix}_ui/v1/users/*/`).as('user'); - cy.contains('testUser').click(); - cy.wait('@user'); - cy.get('[data-cy="DataForm-field-first_name"]').contains('new_first_name'); - cy.get('[data-cy="DataForm-field-last_name"]').contains('new_last_name'); - cy.get('[data-cy="DataForm-field-email"]').contains( - 'new_example@example.com', - ); - }); - - it('deletes user', () => { - cy.visit(`${uiPrefix}users`); - cy.contains('testUser').click(); - cy.contains('Delete').click(); - cy.get('[data-cy="delete-button"]').click(); - - cy.contains('testUser').should('not.exist'); - }); -}); diff --git a/cypress/e2e/namespaces/user-filter.js b/cypress/e2e/namespaces/user-filter.js deleted file mode 100644 index 04e097e9..00000000 --- a/cypress/e2e/namespaces/user-filter.js +++ /dev/null @@ -1,111 +0,0 @@ -describe('Search for users', () => { - beforeEach(() => { - cy.login(); - cy.menuGo('User Access > Users'); - }); - - const usernamefilterInput = () => - cy.get('input[aria-label="username__contains"]').click(); - const firstnamefilterInput = () => - cy.get('input[aria-label="first_name__contains"]').click(); - const lastnamefilterInput = () => - cy.get('input[aria-label="last_name__contains"]').click(); - const emailfilterInput = () => - cy.get('input[aria-label="email__contains"]').click(); - const checkUserEntry = () => - cy - .get('tbody > tr[data-cy="UserList-row-new_user"] > td > a') - .contains('new_user') - .should('be.visible'); - const search = () => - cy - .get( - '.pf-v5-c-toolbar__item > .pf-v5-c-input-group .pf-v5-c-button.pf-m-control', - ) - .click(); - const filterDropdown = () => - cy - .get('.pf-v5-c-toolbar__item > .pf-v5-c-input-group > .pf-v5-c-dropdown') - .click(); - const chooseField = () => cy.get('.pf-v5-c-dropdown__menu > li > a'); - const emptyState = () => - cy - .get('.pf-v5-c-empty-state__content .pf-v5-c-empty-state__title-text') - .should('have.text', 'No results found'); - - it('filters users', () => { - // should have title - cy.assertTitle('Users'); - - // creates a new user - cy.createUser( - 'new_user', - 'veryhardpassword', - 'first_name', - 'last_name', - 'new_user@example.com', - ); - - // filters by username - usernamefilterInput().type('new_user'); - search(); - checkUserEntry(); - usernamefilterInput().clear().type('new_us'); - search(); - checkUserEntry(); - usernamefilterInput().clear().type('new_userrrrr'); - search(); - emptyState(); - cy.contains('.pf-v5-c-chip-group.pf-m-category', 'Username') - .get('button[data-ouia-component-id=close]') - .click(); - - // filters by first name - filterDropdown(); - chooseField().contains('First name').click(); - firstnamefilterInput().type('first_name'); - search(); - checkUserEntry(); - firstnamefilterInput().clear().type('first_na'); - search(); - checkUserEntry(); - firstnamefilterInput().clear().type('first_nammmmm'); - search(); - emptyState(); - cy.contains('.pf-v5-c-chip-group.pf-m-category', 'First name') - .get('button[data-ouia-component-id=close]') - .click(); - - // filters by last name - filterDropdown(); - chooseField().contains('Last name').click(); - lastnamefilterInput().type('last_name'); - search(); - checkUserEntry(); - lastnamefilterInput().clear().type('last_na'); - search(); - checkUserEntry(); - lastnamefilterInput().clear().type('last_nammmmm'); - search(); - emptyState(); - cy.contains('.pf-v5-c-chip-group.pf-m-category', 'Last name') - .get('button[data-ouia-component-id=close]') - .click(); - - // filters by email - filterDropdown(); - chooseField().contains('Email').click(); - emailfilterInput().type('new_user@example.com'); - search(); - checkUserEntry(); - emailfilterInput().clear().type('new_user@example'); - search(); - checkUserEntry(); - emailfilterInput().clear().type('new_user@example.commmm'); - search(); - emptyState(); - cy.contains('.pf-v5-c-chip-group.pf-m-category', 'Email') - .get('button[data-ouia-component-id=close]') - .click(); - }); -}); diff --git a/cypress/e2e/namespaces/user-list.js b/cypress/e2e/namespaces/user-list.js deleted file mode 100644 index c8dc6300..00000000 --- a/cypress/e2e/namespaces/user-list.js +++ /dev/null @@ -1,77 +0,0 @@ -import { range } from 'lodash'; - -const uiPrefix = Cypress.env('uiPrefix'); - -describe('User list tests for sorting, paging and filtering', () => { - const items = []; - - before(() => { - range(20).forEach((i) => { - const name = 'user_test' + i; - items.push(name); - }); - - items.push('admin'); - - items.sort(); - }); - - beforeEach(() => { - cy.login(); - cy.visit(`${uiPrefix}users`); - }); - - it('table contains all columns', () => { - [ - 'Username', - 'First name', - 'Last name', - 'Email', - 'Groups', - 'Created', - ].forEach((item) => { - cy.get('tr[data-cy="SortTable-headers"] th').contains(item); - }); - }); - - it('table contains some time informations for new users', () => { - cy.contains('a few seconds ago'); - }); - - it('paging', () => { - cy.get('.pulp-section').contains(items[0]); - - cy.get('.pulp-section').get('[aria-label="Go to next page"]:first').click(); - cy.get('.pulp-section').contains(items[10]); - - cy.get('.pulp-section').get('[aria-label="Go to next page"]:first').click(); - cy.get('.pulp-section').contains(items[20]); - }); - - it('sorting', () => { - cy.get('.pulp-section').get('[data-cy="sort_username"]').click(); - cy.get('.pulp-section tbody tr:first td:first').contains(items[20]); - cy.get('.pulp-section').contains(items[0]).should('not.exist'); - }); - - it('filter', () => { - cy.get('.pulp-section') - .get('[aria-label="username__contains"]:first') - .type('user_test0{enter}'); - cy.get('.pulp-section').contains('user_test0'); - cy.get('.pulp-section').contains('user_test1').should('not.exist'); - }); - - it('set page size', () => { - cy.get('.pulp-section') - .get('[data-ouia-component-type="PF5/Pagination"] button:first') - .click(); - cy.get('.pulp-section').contains('20 per page').click(); - - range(20).forEach((i) => { - cy.get('.pulp-section').contains(items[i]); - }); - - cy.get('.pulp-section').contains(items[20]).should('not.exist'); - }); -}); diff --git a/cypress/e2e/repo/container-signing.js b/cypress/e2e/repo/container-signing.js deleted file mode 100644 index d32deef2..00000000 --- a/cypress/e2e/repo/container-signing.js +++ /dev/null @@ -1,86 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Container Signing', () => { - const user = 'EESignTestUser'; - const password = 'MyPassword123'; - - before(() => { - cy.login(); - - // user without sign privilleges - cy.addRemoteContainer({ - name: 'remote1', - upstream_name: 'pulp/test-fixture-1', - registry: 'docker', - exclude_tags: '*-source', - }); - - cy.addRemoteContainer({ - name: 'remote2', - upstream_name: 'pulp/test-fixture-1', - registry: 'docker', - exclude_tags: '*-source', - }); - - cy.addLocalContainer('local1', 'pulp/test-fixture-1:manifest_a'); - - // prepare containers for signing - sync them - cy.syncRemoteContainer('remote1'); - // remote 2 is not synced intentionaly - we need test that throws error - }); - - it('can sign remote1', () => { - cy.login(); - cy.visit(`${uiPrefix}containers/remote1`); - cy.contains('[data-cy="column-section"]', 'remote1'); - cy.contains('.pulp-header-bottom', 'Unsigned', { - timeout: 10000, - }); - - cy.contains('Last updated from registry'); - - cy.get('button[aria-label="Actions"]').click(); - cy.contains('.pf-v5-c-dropdown ul li a', 'Sign').click(); - cy.contains('Signing started for container "remote1'); - cy.contains('.pulp-header-bottom', 'Signed', { - timeout: 30000, - }); - }); - - it('can not sign remote2', () => { - cy.login(); - cy.visit(`${uiPrefix}containers/remote2`); - cy.contains('[data-cy="column-section"]', 'remote2'); - cy.contains('.pulp-header-bottom', 'Unsigned', { - timeout: 10000, - }); - - cy.get('button[aria-label="Actions"]').click(); - cy.contains('.pf-v5-c-dropdown ul li a', 'Sign').click(); - cy.contains('Container must be synchronized with remote repository first.'); - }); - - it('can sign local', () => { - cy.login(); - cy.visit(`${uiPrefix}containers/local1`); - cy.contains('[data-cy="column-section"]', 'local1'); - cy.contains('.pulp-header-bottom', 'Unsigned', { - timeout: 10000, - }); - - cy.get('button[aria-label="Actions"]').click(); - cy.contains('.pf-v5-c-dropdown ul li a', 'Sign').click(); - cy.contains('Signing started for container "local1'); - cy.contains('.pulp-header-bottom', 'Signed', { - timeout: 30000, - }); - }); - - it('cant see sign button when user has no rights', () => { - cy.login(user, password); - cy.visit(`${uiPrefix}containers/local1`); - // this is now covered by alert that should not be here in the future - cy.get('button[aria-label="Actions"]').click({ force: true }); - cy.contains('[role=menu] li', 'Sign').should('not.exist'); - }); -}); diff --git a/cypress/e2e/repo/imports-filter-search.js b/cypress/e2e/repo/imports-filter-search.js deleted file mode 100644 index 763555ed..00000000 --- a/cypress/e2e/repo/imports-filter-search.js +++ /dev/null @@ -1,119 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Imports filter test', () => { - beforeEach(() => { - cy.login(); - cy.visit(`${uiPrefix}my-imports?namespace=filter_test_namespace`); - }); - - it('partial filter for name', () => { - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/ansible/search/collection-versions/?*`, - ).as('wait'); - - cy.get('input[aria-label="keywords"').type('my_collection{enter}'); - cy.wait('@wait'); - - cy.get('[data-cy="import-list-data"]') - .contains('different_name') - .should('not.exist'); - cy.get('[data-cy="import-list-data"]').contains('my_collection1'); - cy.get('[data-cy="import-list-data"]').contains('my_collection2'); - }); - - it('exact filter for name', () => { - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/ansible/search/collection-versions/?*`, - ).as('wait'); - - cy.get('input[aria-label="keywords"').type('my_collection1{enter}'); - cy.wait('@wait'); - - cy.get('[data-cy="import-list-data"]') - .contains('my_collection2') - .should('not.exist'); - cy.get('[data-cy="import-list-data"]') - .contains('different_name') - .should('not.exist'); - cy.get('[data-cy="import-list-data"]').contains('my_collection1'); - }); - - it('Exact search for completed', () => { - cy.get('[data-cy="compound_filter"] button:first').click(); - cy.contains('[data-cy="compound_filter"] a', 'Status').click(); - - cy.get('[data-cy="compound_filter"] button').eq(1).click(); - - // waiting to another query, otherwise sporadic failuers - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/ansible/search/collection-versions/?namespace=*`, - ).as('wait'); - cy.contains('[data-cy="compound_filter"] a', 'Completed').click(); - - cy.wait('@wait'); - - cy.get('[data-cy="import-list-data"]').contains('my_collection1'); - cy.get('[data-cy="import-list-data"]').contains('my_collection2'); - cy.get('[data-cy="import-list-data"]').contains('different_name'); - }); - - it('Exact search for waiting', () => { - cy.get('[data-cy="compound_filter"] button:first').click(); - cy.contains('[data-cy="compound_filter"] a', 'Status').click(); - - cy.get('[data-cy="compound_filter"] button').eq(1).click(); - cy.contains('[data-cy="compound_filter"] a', 'Waiting').click(); - cy.contains('No results found'); - }); - - it('Exact search for name and completed', () => { - cy.get('[data-cy="compound_filter"] input[aria-label="keywords"').type( - 'my_collection1{enter}', - ); - cy.get('[data-cy="compound_filter"] button:first').click(); - cy.contains('[data-cy="compound_filter"] a', 'Status').click(); - - cy.get('[data-cy="compound_filter"] button').eq(1).click(); - - // waiting to another query, otherwise sporadic failuers - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/ansible/search/collection-versions/?namespace=*`, - ).as('wait'); - cy.contains('a', 'Completed').click(); - - cy.wait('@wait'); - - cy.get('[data-cy="import-list-data"]') - .contains('different_name') - .should('not.exist'); - cy.get('[data-cy="import-list-data"]').contains('my_collection1'); - }); - - it('Partial search for name and completed', () => { - cy.get('[data-cy="compound_filter"] input[aria-label="keywords"').type( - 'my_collection{enter}', - ); - cy.get('[data-cy="compound_filter"] button:first').click(); - cy.contains('[data-cy="compound_filter"] a', 'Status').click(); - - cy.get('[data-cy="compound_filter"] button').eq(1).click(); - - // waiting to another query, otherwise sporadic failuers - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/ansible/search/collection-versions/?namespace=*`, - ).as('wait'); - cy.contains('a', 'Completed').click(); - cy.wait('@wait'); - - cy.get('[data-cy="import-list-data"]').contains('my_collection2'); - cy.get('[data-cy="import-list-data"]') - .contains('different_name') - .should('not.exist'); - }); -}); diff --git a/cypress/e2e/repo/imports-filter.js b/cypress/e2e/repo/imports-filter.js deleted file mode 100644 index ecfc1689..00000000 --- a/cypress/e2e/repo/imports-filter.js +++ /dev/null @@ -1,84 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Imports filter test', () => { - const testCollection = `test_collection_${Math.random() - .toString(36) - .replace(/[^a-z]+/g, '')}`; - - before(() => { - cy.login(); - - // insert test data - }); - - beforeEach(() => { - cy.login(); - cy.visit(`${uiPrefix}my-imports?namespace=filter_test_namespace`); - }); - - it('should display success info after importing collection', () => { - cy.visit(`${uiPrefix}my-imports?namespace=test_namespace`); - - cy.get(`[data-cy="ImportList-row-${testCollection}"]`).click(); - cy.get('[data-cy="MyImports"]').contains( - `test_namespace.${testCollection}`, - ); - cy.get( - '[data-cy="MyImports"] [data-cy="ImportConsole"] .title-bar', - ).contains('Completed', { timeout: 10000 }); - cy.get( - '[data-cy="MyImports"] [data-cy="ImportConsole"] .message-list', - ).contains('Done'); - }); - - it('should be able to switch between namespaces', () => { - cy.get('button[aria-label="Clear all"]').click(); - cy.contains('[data-cy="import-list-data"]', 'No namespace selected.', { - timeout: 8000, - }); - - cy.intercept( - 'GET', - `${apiPrefix}_ui/v1/imports/collections/?namespace=test_namespace&*`, - ).as('collectionsInNamespace'); - cy.intercept('GET', `${apiPrefix}_ui/v1/imports/collections/*`).as( - 'collectionDetail', - ); - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/ansible/search/collection-versions/?namespace=test_namespace&name=*`, - ).as('collectionVersions'); - - cy.get('[placeholder="Select namespace"]').clear(); - cy.get('[placeholder="Select namespace"]').type('test_namespace'); - cy.contains('button', 'test_namespace').click(); - - cy.wait('@collectionsInNamespace'); - cy.wait('@collectionDetail'); - cy.wait('@collectionVersions'); - - cy.get(`[data-cy="ImportList-row-${testCollection}"]`).should('be.visible'); - - cy.intercept( - 'GET', - `${apiPrefix}_ui/v1/imports/collections/?namespace=filter_test_namespace&*`, - ).as('collectionsInNamespace2'); - cy.intercept('GET', `${apiPrefix}_ui/v1/imports/collections/*`).as( - 'collectionDetail2', - ); - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/ansible/search/collection-versions/?namespace=filter_test_namespace&name=*`, - ).as('collectionVersions2'); - - cy.get('[placeholder="Select namespace"]').click(); - cy.contains('button', 'filter_test_namespace').click(); - - cy.wait('@collectionsInNamespace2'); - cy.wait('@collectionDetail2'); - cy.wait('@collectionVersions2'); - - cy.get('[data-cy="ImportList-row-my_collection1"]').should('be.visible'); - }); -}); diff --git a/cypress/e2e/repo/remote-registry.js b/cypress/e2e/repo/remote-registry.js deleted file mode 100644 index 0c033b6c..00000000 --- a/cypress/e2e/repo/remote-registry.js +++ /dev/null @@ -1,128 +0,0 @@ -const apiPrefix = Cypress.env('apiPrefix'); -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Remote Registry Tests', () => { - before(() => { - cy.visit(uiPrefix); - cy.login(); - }); - - beforeEach(() => { - cy.visit(uiPrefix); - cy.login(); - }); - - it('checks for empty state', () => { - cy.menuGo('Containers > Remote Registries'); - cy.get( - '.pf-v5-c-empty-state__content .pf-v5-c-empty-state__title-text', - ).should('have.text', 'No remote registries yet'); - cy.get('.pf-v5-c-empty-state__content > .pf-v5-c-empty-state__body').should( - 'have.text', - 'You currently have no remote registries.', - ); - }); - - it('admin can add new remote registry', () => { - cy.menuGo('Containers > Remote Registries'); - - cy.addRemoteRegistry('New remote registry1', 'https://some url1'); - cy.addRemoteRegistry('New remote registry2', 'https://some url2', { - username: 'some username2', - password: 'some password2', - proxy_url: 'https://some proxy_url2', - proxy_username: 'some proxy_username2', - proxy_password: 'some proxy_password2', - download_concurrency: 5, - rate_limit: 5, - }); - }); - - it('admin can view data', () => { - cy.visit(`${uiPrefix}registries`); - - // table headers - cy.contains('Remote Registries'); - [ - 'Name', - 'Created', - 'Last updated', - 'Registry URL', - 'Registry sync status', - ].forEach((element) => { - cy.contains('tr[data-cy="SortTable-headers"]', element); - }); - - cy.contains('table tr', 'New remote registry1'); - cy.contains('table tr', 'New remote registry2'); - cy.contains('table tr', 'https://some url1'); - cy.contains('table tr', 'https://some url2'); - }); - - it('user can sync succesfully remote registry', () => { - cy.visit(`${uiPrefix}registries`); - - cy.intercept( - 'POST', - `${apiPrefix}_ui/v1/execution-environments/registries/*/sync`, - ).as('sync'); - - cy.get( - '[data-cy="ExecutionEnvironmentRegistryList-row-New remote registry1"]', - ) - .contains('Sync from registry') - .click(); - - cy.wait('@sync'); - - cy.get('[data-cy="AlertList"]').contains( - 'Sync started for remote registry "New remote registry1".', - ); - - cy.get( - '[data-cy="ExecutionEnvironmentRegistryList-row-New remote registry1"]', - ).contains('Completed', { timeout: 10000 }); - }); - - it('admin can edit new remote registry', () => { - cy.menuGo('Containers > Remote Registries'); - - cy.get( - 'tr[data-cy="ExecutionEnvironmentRegistryList-row-New remote registry1"] button[aria-label="Actions"]', - ).click(); - cy.contains('a', 'Edit').click(); - - cy.get('input[id = "url"]').clear(); - cy.get('input[id = "url"]').type('https://some new url2'); - - // edit advanced options - cy.contains('Show advanced options').click(); - - cy.get('input[id="username"]').type('test'); - cy.get('input[id="password"]').type('test'); - cy.get('input[id="proxy_url"]').type('https://example.org'); - cy.get('input[id="proxy_username"]').type('test'); - cy.get('input[id="proxy_password"]').type('test'); - - cy.intercept( - 'GET', - `${apiPrefix}_ui/v1/execution-environments/registries/?*`, - ).as('registriesGet'); - - cy.contains('button', 'Save').click(); - cy.wait('@registriesGet'); - - // verify url change in list view - cy.visit(`${uiPrefix}registries`); - cy.contains('table tr', 'https://some new url2'); - - // verify advanced option values have been saved properly. - cy.get('[aria-label="Actions"]:first').click(); - cy.contains('Edit').click(); - cy.contains('Show advanced options').click(); - cy.get('[data-cy="username"]').children().contains('Clear'); - cy.get('input[id="proxy_url"]').should('have.value', 'https://example.org'); - cy.get('[data-cy="proxy_username"]').children().contains('Clear'); - cy.contains('Save').click(); - }); -}); diff --git a/cypress/e2e/repo/repository-list.js b/cypress/e2e/repo/repository-list.js deleted file mode 100644 index 8c81ac12..00000000 --- a/cypress/e2e/repo/repository-list.js +++ /dev/null @@ -1,164 +0,0 @@ -import { range } from 'lodash'; - -const uiPrefix = Cypress.env('uiPrefix'); - -describe('Repository', () => { - before(() => { - // chrome only - prevent 'Write permission denied.' when copying to clipboard - cy.wrap( - Cypress.automation('remote:debugger:protocol', { - command: 'Browser.grantPermissions', - params: { - permissions: ['clipboardReadWrite', 'clipboardSanitizedWrite'], - origin: window.location.origin, - }, - }), - ); - }); - - beforeEach(() => { - cy.login(); - cy.visit(`${uiPrefix}ansible/repositories/`); - }); - - it('tests Paging and sorting', () => { - cy.contains('[data-cy="ListPage-AnsibleRepositoryList"]', '1 - 10 of 11'); - cy.get( - '[data-cy="ListPage-AnsibleRepositoryList"] [data-cy="sort_name"]', - ).click(); - - cy.contains('repoListTest1'); - cy.contains('certified'); - cy.contains('validated'); - cy.contains('repoListTest3'); - cy.contains('community').should('not.exist'); - - cy.get( - '[data-cy="ListPage-AnsibleRepositoryList"] [data-action="next"]:first', - ).click(); - cy.contains('[data-cy="ListPage-AnsibleRepositoryList"]', '11 of 11'); - - cy.contains('repoListTest1').should('not.exist'); - cy.contains('certified').should('not.exist'); - cy.contains('validated').should('not.exist'); - cy.contains('repoListTest3').should('not.exist'); - cy.contains('community'); - - cy.visit(`${uiPrefix}ansible/repositories/`); - cy.get( - '[data-cy="ListPage-AnsibleRepositoryList"] [data-cy="sort_name"]', - ).click(); - cy.get( - '[data-cy="ListPage-AnsibleRepositoryList"] [data-cy="sort_name"]', - ).click(); - - cy.contains('repoListTest1'); - cy.contains('certified'); - cy.contains('validated').should('not.exist'); - cy.contains('repoListTest3'); - cy.contains('community'); - - cy.get( - '[data-cy="ListPage-AnsibleRepositoryList"] [data-action="next"]:first', - ).click(); - - cy.contains('repoListTest1').should('not.exist'); - cy.contains('certified').should('not.exist'); - cy.contains('validated'); - cy.contains('repoListTest3').should('not.exist'); - cy.contains('community').should('not.exist'); - }); - - it('tests filtering', () => { - cy.get( - '[data-cy="ListPage-AnsibleRepositoryList"] [data-cy="sort_name"]', - ).click(); - cy.get('[data-cy="compound_filter"] input') - .clear() - .type('repoListTest{enter}'); - range(5).forEach((i) => { - cy.contains('repoListTest' + i); - }); - cy.contains('community').should('not.exist'); - cy.contains('validated').should('not.exist'); - cy.contains('certified').should('not.exist'); - - cy.get('[data-cy="compound_filter"] input') - .clear() - .type('repoListTest4{enter}'); - cy.contains('repoListTest4'); - cy.contains('repoListTest0').should('not.exist'); - cy.contains('repoListTest1').should('not.exist'); - cy.contains('community').should('not.exist'); - cy.contains('validated').should('not.exist'); - cy.contains('certified').should('not.exist'); - - cy.contains('Clear all filters').click(); - - cy.contains('repoListTest4'); - cy.contains('repoListTest0'); - cy.contains('repoListTest1'); - cy.contains('community').should('not.exist'); - cy.contains('validated'); - cy.contains('certified'); - - cy.get('[data-cy="compound_filter"] input').clear().type('test{enter}'); - - range(5).forEach((i) => { - cy.contains('repoListTest' + i); - }); - - cy.contains('community').should('not.exist'); - cy.contains('validated').should('not.exist'); - cy.contains('certified').should('not.exist'); - }); - - it('tests deletion', () => { - cy.get('[data-cy="compound_filter"] input') - .clear() - .type('repoListTest4{enter}'); - cy.get( - '[data-cy="ListPage-AnsibleRepositoryList"] [aria-label="Actions"]', - ).click(); - cy.contains( - '[data-cy="ListPage-AnsibleRepositoryList"] a', - 'Delete', - ).click(); - cy.contains('Delete repository?'); - cy.contains('[data-cy="delete-button"] button', 'Delete').click(); - cy.contains('Removal started for repository repoListTest4'); - cy.wait(5000); - cy.visit(`${uiPrefix}ansible/repositories/`); - cy.get('[data-cy="compound_filter"] input') - .clear() - .type('repoListTest4{enter}'); - cy.contains('No results found'); - }); - - it('tests edit', () => { - cy.get('[data-cy="compound_filter"] input') - .clear() - .type('repoListTest3{enter}'); - cy.get( - '[data-cy="ListPage-AnsibleRepositoryList"] [aria-label="Actions"]', - ).click(); - cy.contains('[data-cy="ListPage-AnsibleRepositoryList"] a', 'Edit').click(); - cy.get('[data-cy="Page-AnsibleRepositoryEdit"]'); - }); - - it('tests CLI config', () => { - cy.get('[data-cy="compound_filter"] input') - .clear() - .type('repoListTest3{enter}'); - cy.get( - '[data-cy="ListPage-AnsibleRepositoryList"] [aria-label="Actions"]', - ).click(); - cy.contains( - '[data-cy="ListPage-AnsibleRepositoryList"] a', - 'Copy CLI configuration', - ) - .focus() - .click(); - cy.contains('Successfully copied to clipboard'); - }); -}); diff --git a/cypress/e2e/repo/repository.js b/cypress/e2e/repo/repository.js deleted file mode 100644 index 61cb3671..00000000 --- a/cypress/e2e/repo/repository.js +++ /dev/null @@ -1,182 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); - -function versionCheck(version) { - cy.login(); - cy.visit(`${uiPrefix}ansible/repositories/repo1Test/`); - cy.contains('a', 'Versions').click(); - cy.get( - '[data-cy="PageWithTabs-AnsibleRepositoryDetail-repository-versions"]', - ); - cy.contains( - '[data-cy="PageWithTabs-AnsibleRepositoryDetail-repository-versions"]', - version + ' (latest)', - ); -} - -['with remote', 'without remote'].forEach((mode) => { - const withRemote = mode === 'with remote'; - - describe(`Repository ${mode}`, () => { - it('creates, edit and sync repository', () => { - cy.login(); - - cy.contains('Repositories'); - cy.contains('button', 'Add repository').click(); - cy.contains('Add new repository'); - cy.get('[data-cy="Page-AnsibleRepositoryEdit"] input[id="name"]').type( - 'repo1Test', - ); - cy.get( - '[data-cy="Page-AnsibleRepositoryEdit"] input[id="description"]', - ).type('repo1Test description'); - - cy.get('[data-cy="pipeline"] button').click(); - cy.contains('[data-cy="pipeline"]', 'Staging'); - cy.contains('[data-cy="pipeline"]', 'Approved'); - cy.contains('[data-cy="pipeline"]', 'None'); - - cy.contains('[data-cy="pipeline"] button', 'Approved').click(); - cy.contains( - '[data-cy="Page-AnsibleRepositoryEdit"] button', - 'Save', - ).click(); - - // check if created correctly - cy.visit(`${uiPrefix}ansible/repositories/`); - cy.contains('Repositories'); - cy.contains('repo1Test'); - cy.contains('a', 'repo1Test').click(); - cy.contains( - '[data-cy="PageWithTabs-AnsibleRepositoryDetail-details"]', - 'repo1Test description', - ); - cy.contains( - '[data-cy="PageWithTabs-AnsibleRepositoryDetail-details"]', - 'pipeline: approved', - ); - - // try to edit it - cy.contains('Edit').click(); - cy.get( - '[data-cy="Page-AnsibleRepositoryEdit"] input[id="retain_repo_versions"]', - ) - .clear() - .type('5'); - - if (withRemote) { - // add remote - cy.get('[data-cy="remote"] button').click(); - cy.contains('[data-cy="remote"]', 'certified'); - cy.contains('[data-cy="remote"]', 'community'); - cy.contains( - '[data-cy="remote"] button', - 'exampleTestRepository', - ).click(); - } - - cy.contains( - '[data-cy="Page-AnsibleRepositoryEdit"] button', - 'Save', - ).click(); - - // check if edited correctly - cy.visit(`${uiPrefix}ansible/repositories/repo1Test/`); - cy.contains( - '[data-cy="PageWithTabs-AnsibleRepositoryDetail-details"]', - '5', - ); - - if (withRemote) { - // try to sync it, expect failure - cy.contains('button', 'Sync').click(); - cy.get('.pf-v5-c-modal-box__footer .pf-m-primary') - .contains('Sync') - .click(); - - cy.contains('Sync started for repository "repo1Test".'); - cy.contains('a', 'detail page').click(); - cy.get('.pf-v5-c-label__content').contains('Failed', { - timeout: 15000, - }); - } - }); - - it('checks there is only 1 version', () => { - versionCheck(0); - }); - - it('adds collections', () => { - cy.login(); - cy.visit(`${uiPrefix}ansible/repositories/repo1Test/`); - cy.contains('a', 'Collection versions').click(); - cy.contains('button', 'Add collection').click(); - cy.contains('Select a collection'); - cy.get('input[aria-label="keywords"]') - .clear() - .type('repo_test_collection{enter}'); - - cy.get( - 'input[aria-label="repo_test_namespace.repo_test_collection v1.0.0"]', - ).click(); - cy.contains('button', 'Select').click(); - cy.contains( - 'Started adding repo_test_namespace.repo_test_collection v1.0.0 from "published" to repository "repo1Test".', - ); - cy.contains('a', 'detail page').click(); - cy.contains('Completed'); - }); - - it('checks there are 2 versions and collection is here', () => { - versionCheck(1); - cy.contains( - '[data-cy="PageWithTabs-AnsibleRepositoryDetail-repository-versions"] a', - 1, - ).click(); - cy.contains( - '[data-cy="PageWithTabs-AnsibleRepositoryDetail-repository-versions"]', - 'repo_test_namespace.repo_test_collection v1.0.0', - ); - }); - - it('removes collections', () => { - cy.login(); - cy.visit( - `${uiPrefix}ansible/repositories/repo1Test/?tab=collection-versions`, - ); - cy.contains('repo_test_collection'); - cy.get('[aria-label="Actions"]').click(); - cy.contains('a', 'Remove').click(); - cy.contains('Remove collection version?'); - cy.contains('button', 'Remove').click(); - }); - - it('checks if collection was removed', () => { - cy.login(); - cy.visit( - `${uiPrefix}ansible/repositories/repo1Test/?tab=collection-versions`, - ); - cy.contains('repo_test_collection').should('not.exist'); - cy.contains('No collection versions yet'); - }); - - it('checks there are 3 versions and revert repo', () => { - versionCheck(2); - cy.get( - '[data-cy="PageWithTabs-AnsibleRepositoryDetail-repository-versions"] [aria-label="Actions"]', - ) - .eq(1) - .click(); - cy.contains('a', 'Revert to this version').click(); - cy.contains('button', 'Revert').click(); - }); - - it('checks if collection is added again', () => { - cy.login(); - cy.visit( - `${uiPrefix}ansible/repositories/repo1Test/?tab=collection-versions`, - ); - cy.contains('repo_test_collection'); - cy.contains('No collection versions yet').should('not.exist'); - }); - }); -}); diff --git a/cypress/e2e/screenshots/screenshots.js b/cypress/e2e/screenshots/screenshots.js deleted file mode 100644 index 0b7dff05..00000000 --- a/cypress/e2e/screenshots/screenshots.js +++ /dev/null @@ -1,42 +0,0 @@ -const uiPrefix = Cypress.env('uiPrefix'); - -describe('screenshots', () => { - beforeEach(() => { - cy.login(); - }); - - it('takes screenshots', () => { - const screenshot = (path, options = {}) => { - const filename = path.replaceAll('/', '__').replace(/^__$/, 'root'); - - cy.visit(`${uiPrefix}${path}`.replace('//', '/')); - cy.wait(3000); - cy.screenshot(filename, options); - cy.wait(1000); - }; - - screenshot('/'); - - screenshot('/collections'); - screenshot('/namespaces'); - screenshot('/ansible/repositories', { blackout: ['time'] }); - screenshot('/ansible/remotes'); - screenshot('/token'); - screenshot('/approval'); - screenshot('/my-imports'); - - screenshot('/containers'); - screenshot('/registries'); - - screenshot('/tasks', { blackout: ['time'] }); - screenshot('/signature-keys', { - blackout: ['time', '[data-cy=pulp-signature-list-fingerprint]'], - }); - - screenshot('/users', { blackout: ['time'] }); - screenshot('/group-list'); - screenshot('/roles', { blackout: ['time'] }); - - screenshot('/settings/user-profile'); - }); -}); diff --git a/cypress/e2e/smoke.js b/cypress/e2e/smoke.js new file mode 100644 index 00000000..edeb1806 --- /dev/null +++ b/cypress/e2e/smoke.js @@ -0,0 +1,107 @@ +describe('UI smoke tests', () => { + beforeEach(() => cy.login()); + + it('Logout + login', () => { + cy.ui(); + + // log out via top nav + cy.get('[data-cy=user-dropdown]').click(); + cy.contains('a', 'Logout').click(); + + // go to login via left nav + cy.get('[data-cy=pulp-menu-item-Login]').click(); + cy.assertTitle('Login'); + + // fill in form manually, submit + cy.get('#pf-login-username-id').type(Cypress.env('username')); + cy.get('#pf-login-password-id').type(Cypress.env('password')); + cy.contains('button', 'Log in').click(); + + // check on Status, logged in + cy.assertTitle('Status'); + cy.get('[data-cy=user-dropdown]'); + }); + + it('Navigation', () => { + cy.ui(); + + // TODO + }); + + it('Status', () => { + cy.ui(); + cy.assertTitle('Status'); + + cy.contains('Online workers'); + }); + + it('Ansible repositories', () => { + cy.ui('ansible/repositories'); + cy.assertTitle('Repositories'); + + // TODO + }); + + it('Ansible remotes', () => { + cy.ui('ansible/remotes'); + cy.assertTitle('Remotes'); + + // TODO + }); + + it('File repositories', () => { + cy.ui('file/repositories'); + cy.assertTitle('Repositories'); + + // TODO + }); + + it('File remotes', () => { + cy.ui('file/remotes'); + cy.assertTitle('Remotes'); + + // TODO + }); + + it('RPMs', () => { + cy.ui('rpm/rpms'); + cy.assertTitle('Packages'); + + cy.contains('No packages yet'); + }); + + it('Task management', () => { + cy.ui('tasks'); + cy.assertTitle('Task management'); + + // TODO + }); + + it('Users', () => { + cy.ui('users'); + cy.assertTitle('Users'); + + // TODO + }); + + it('Groups', () => { + cy.ui('groups'); + cy.assertTitle('Groups'); + + // TODO + }); + + it('Roles', () => { + cy.ui('roles'); + cy.assertTitle('Roles'); + + // TODO + }); + + it('About project', () => { + cy.ui('about'); + cy.assertTitle('About project'); + + // TODO + }); +}); diff --git a/cypress/plugins/console-logger.js b/cypress/plugins/console-logger.js deleted file mode 100644 index 43350bc3..00000000 --- a/cypress/plugins/console-logger.js +++ /dev/null @@ -1,58 +0,0 @@ -const CDP = require('chrome-remote-interface'); - -function logConsole({ args }) { - console.log(...args.map((arg) => arg.value || arg.preview || arg)); -} - -function isChrome(browser) { - return ['chrome', 'chromium'].includes(browser.family); -} - -function ensureRdpPort(args) { - const existing = args.find((arg) => - arg.startsWith('--remote-debugging-port'), - ); - if (existing) { - return Number(existing.split('=')[1]); - } - - const port = 40000 + Math.round(Math.random() * 25000); - args.push(`--remote-debugging-port=${port}`); - return port; -} - -function browserLaunchHandler(browser = {}, launchOptions) { - if (!isChrome(browser)) { - return console.log('unsupported browser', browser); - } - - const args = launchOptions.args || launchOptions; - const rdp = ensureRdpPort(args); - - const tryConnect = () => { - new CDP({ - port: rdp, - }) - .then((cdp) => { - console.log('Connected to Chrome Debugging Protocol'); - - /** captures logs from console.X calls */ - cdp.Runtime.enable(); - cdp.Runtime.consoleAPICalled(logConsole); - - cdp.on('disconnect', () => { - console.log('Chrome Debugging Protocol disconnected'); - }); - }) - .catch(() => { - setTimeout(tryConnect, 100); - }); - }; - - tryConnect(); - return launchOptions; -} - -module.exports = { - install: (on) => on('before:browser:launch', browserLaunchHandler), -}; diff --git a/cypress/support/commands.js b/cypress/support/commands.js deleted file mode 100644 index 87597d18..00000000 --- a/cypress/support/commands.js +++ /dev/null @@ -1,234 +0,0 @@ -// https://on.cypress.io/custom-commands -import shell from 'shell-escape-tag'; - -const apiPrefix = Cypress.env('apiPrefix'); - -Cypress.Commands.add('containsnear', {}, (...args) => { - if (args.length >= 2) { - if (typeof args[0] === 'string' && typeof args[1] === 'string') { - return cy.get(`*:has(${args[0]})`).contains(...args.slice(1)); - } - } - cy.log('constainsnear requires selector and content parameters'); -}); - -const name2element = (name) => { - const [first, last] = name.split(' > '); - return last - ? cy.get( - `#page-sidebar [data-cy="pulp-menu-section-${first}"] [data-cy="pulp-menu-item-${last}"]`, - ) - : cy.get(`#page-sidebar [data-cy="pulp-menu-item-${first}"]`); -}; - -Cypress.Commands.add('menuPresent', {}, (name) => { - return name2element(name).should('exist'); -}); - -Cypress.Commands.add('menuMissing', {}, (name) => { - return name2element(name).should('not.exist'); -}); - -Cypress.Commands.add('menuGo', {}, (name) => { - return name2element(name).click({ force: true }); -}); - -Cypress.Commands.add('assertTitle', {}, (title) => { - cy.contains('.pf-v5-c-title', title); -}); - -Cypress.Commands.add('openHeaderKebab', {}, () => { - cy.wait(500); // the collection detaill displays the kebab before all apis are loaded, repaints after.. just wait - cy.scrollTo(0, 0, { ensureScrollable: false }); - cy.get('[data-cy="kebab-toggle"] [aria-label="Actions"]').click(); -}); - -Cypress.Commands.add( - 'createUser', - {}, - ( - username, - password = null, - firstName = null, - lastName = null, - email = null, - ) => { - cy.menuGo('User Access > Users'); - - const user = { - firstName: firstName || 'First Name', - lastName: lastName || 'Last Name', - username, - email: email || 'firstName@example.com', - password: password || 'I am a complicated passw0rd', - }; - cy.contains('Create').click(); - cy.get('#first_name').type(user.firstName); - cy.get('#last_name').type(user.lastName); - cy.get('#email').type(user.email); - cy.get('#username').type(user.username); - cy.get('#password').type(user.password); - cy.get('#password-confirm').type(user.password); - - cy.intercept('POST', `${apiPrefix}_ui/v1/users/`).as('createUser'); - - cy.contains('Save').click(); - cy.wait('@createUser'); - - // Wait for navigation - cy.assertTitle('Users'); - }, -); - -Cypress.Commands.add('addRemoteRegistry', {}, (name, url, extra = null) => { - cy.menuGo('Containers > Remote Registries'); - cy.contains('button', 'Add remote registry').click(); - - // add registry - cy.get('input[id="name"]').type(name); - cy.get('input[id="url"]').type(url); - - if (extra) { - const { - username, - password, - proxy_url, - proxy_username, - proxy_password, - download_concurrency, - rate_limit, - } = extra; - - cy.get('input[id="username"]').type(username); - cy.get('input[id="password"]').type(password); - - // advanced options - cy.get('.pf-v5-c-expandable-section__toggle-text').click(); - cy.get('input[id="proxy_url"]').type(proxy_url); - cy.get('input[id="proxy_username"]').type(proxy_username); - cy.get('input[id="proxy_password"]').type(proxy_password); - cy.get('[data-cy=client_key]'); - cy.get('button[data-cy=client_cert]'); - cy.get('button[data-cy=ca_cert]'); - cy.get('input[id="download_concurrency"]').type(download_concurrency); - cy.get('input[id="rate_limit"]').type(rate_limit); - } - - cy.intercept( - 'POST', - `${apiPrefix}_ui/v1/execution-environments/registries/`, - ).as('registries'); - - cy.intercept( - 'GET', - `${apiPrefix}_ui/v1/execution-environments/registries/?*`, - ).as('registriesGet'); - - cy.contains('button', 'Save').click(); - - cy.wait('@registries'); - cy.wait('@registriesGet'); -}); - -Cypress.Commands.add( - 'addRemoteContainer', - {}, - ({ name, upstream_name, registry, include_tags, exclude_tags }) => { - cy.menuGo('Containers > Containers'); - cy.contains('button', 'Add container').click(); - - // add registry - cy.get('input[id="name"]').type(name); - cy.get('input[id="upstreamName"]').type(upstream_name); - - cy.get( - '.pulp-formgroup-registry .pf-v5-c-form-control.pf-v5-c-select__toggle-typeahead input', - ) - .click() - .type(registry); - cy.contains('button', registry).click(); - - if (include_tags) { - cy.get('input[id="addTagsInclude"]') - .type(include_tags) - .parents('.pf-v5-c-input-group') - .find('button', 'Add') - .click(); - } - - if (exclude_tags) { - cy.get('input[id="addTagsExclude"]') - .type(exclude_tags) - .parents('.pf-v5-c-input-group') - .find('button', 'Add') - .click(); - } - - cy.intercept( - 'POST', - `${apiPrefix}_ui/v1/execution-environments/remotes/`, - ).as('saved'); - - cy.intercept( - 'GET', - `${apiPrefix}v3/plugin/execution-environments/repositories/?*`, - ).as('listLoad'); - - cy.contains('button', 'Save').click(); - - cy.wait('@saved'); - cy.wait('@listLoad'); - }, -); - -Cypress.Commands.add( - 'addLocalContainer', - {}, - (localName, remoteName, registry = 'docker.io/') => { - const log = ({ code, stderr, stdout }) => - console.log(`CODE=${code} ERR=${stderr} OUT=${stdout}`); - const logFail = (...arr) => { - console.log(arr); - return Promise.reject(...arr); - }; - const server = Cypress.env('containers'); - - return cy - .exec(shell`podman pull ${registry + remoteName}`) - .then(log, logFail) - .then(() => - cy.exec( - shell`podman image tag ${remoteName} ${server}/${localName}:latest`, - ), - ) - .then(log, logFail) - .then(() => - cy.exec( - shell`podman login ${server} --tls-verify=false --username=admin --password=admin`, - { failOnNonZeroExit: false }, - ), - ) - .then(log, logFail) - .then(() => - cy.exec( - shell`podman push ${server}/${localName}:latest --tls-verify=false`, - { failOnNonZeroExit: false }, - ), - ) - .then(log, logFail); - }, -); - -Cypress.Commands.add('syncRemoteContainer', {}, (name) => { - cy.menuGo('Containers > Containers'); - cy.contains('tr', name) - .find('button[aria-label="Actions"]') - .click() - .parents('tr') - .contains('.pf-v5-c-dropdown__menu-item', 'Sync from registry') - .click(); - cy.contains('.pf-v5-c-alert__title', `Sync started for container "${name}".`); - // wait for finish - cy.contains('a', 'detail page').click(); - cy.contains('[data-cy="title-box"] h1', 'Completed', { timeout: 30000 }); -}); diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js index 05f42f7c..a4479bdf 100644 --- a/cypress/support/e2e.js +++ b/cypress/support/e2e.js @@ -1,4 +1,27 @@ -// https://on.cypress.io/configuration -import 'cypress-file-upload'; -import './commands'; -import './login'; +// https://on.cypress.io/custom-commands + +// const api = Cypress.env('API_BASE_PATH'); +const ui = Cypress.env('UI_BASE_PATH'); + +Cypress.Commands.add('assertTitle', {}, (title) => { + cy.contains('.pf-v5-c-title', title); +}); + +Cypress.Commands.add('ui', {}, (path = '') => { + cy.visit(ui + path); +}); + +Cypress.Commands.add('login', {}, (username, password) => { + if (!username && !password) { + // default to admin + username = Cypress.env('username'); + password = Cypress.env('password'); + } + + cy.session(username, () => { + window.sessionStorage.credentials = JSON.stringify({ + username, + password, + }); + }); +}); diff --git a/cypress/support/login.js b/cypress/support/login.js deleted file mode 100644 index 7b637f63..00000000 --- a/cypress/support/login.js +++ /dev/null @@ -1,41 +0,0 @@ -// https://on.cypress.io/custom-commands -const apiPrefix = Cypress.env('apiPrefix'); - -function apiLogin(username, password, url = '/', title = 'Collections') { - cy.session( - ['apiLogin', username], - () => { - const loginUrl = `${apiPrefix}_ui/v1/auth/login/`; - cy.request('GET', loginUrl).then(() => { - cy.getCookie('csrftoken').then((csrftoken) => { - cy.request({ - method: 'POST', - url: loginUrl, - body: { username, password }, - headers: { - 'X-CSRFToken': csrftoken.value, - Referer: Cypress.config().baseUrl, - }, - }); - }); - }); - }, - { - validate: () => - cy.request(`${apiPrefix}_ui/v1/me/`).its('status').should('eq', 200), - }, - ); - - cy.visit(url); - cy.assertTitle(title); -} - -Cypress.Commands.add('login', {}, (username, password, url, title) => { - if (!username && !password) { - // default to admin - username = Cypress.env('username'); - password = Cypress.env('password'); - } - - apiLogin(username, password, url, title); -}); diff --git a/package-lock.json b/package-lock.json index 00fc9a2c..451b352a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,12 +38,10 @@ "@ls-lint/ls-lint": "^2.2.3", "@trivago/prettier-plugin-sort-imports": "^5.2.0", "babel-loader": "^9.2.1", - "chrome-remote-interface": "^0.33.2", "clean-webpack-plugin": "^4.0.0", "copy-webpack-plugin": "^12.0.2", "css-loader": "^7.1.2", "cypress": "^13.17.0", - "cypress-file-upload": "^5.0.8", "eslint": "~9.17.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-lingui": "^0.9.0", @@ -57,7 +55,6 @@ "prettier": "^3.4.2", "sass": "1.83.0", "sass-loader": "^16.0.4", - "shell-escape-tag": "^2.0.2", "source-map-loader": "^5.0.0", "style-loader": "^4.0.0", "stylelint": "^16.12.0", @@ -4519,12 +4516,6 @@ "node": ">=4" } }, - "node_modules/any-shell-escape": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/any-shell-escape/-/any-shell-escape-0.1.1.tgz", - "integrity": "sha512-36j4l5HVkboyRhIWgtMh1I9i8LTdFqVwDEHy1cp+QioJyKgAUG40X0W8s7jakWRta/Sjvm8mUG1fU6Tj8mWagQ==", - "dev": true - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -5396,46 +5387,6 @@ "fsevents": "~2.3.1" } }, - "node_modules/chrome-remote-interface": { - "version": "0.33.2", - "resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.33.2.tgz", - "integrity": "sha512-wvm9cOeBTrb218EC+6DteGt92iXr2iY0+XJP30f15JVDhqvWvJEVACh9GvUm8b9Yd8bxQivaLSb8k7mgrbyomQ==", - "dev": true, - "dependencies": { - "commander": "2.11.x", - "ws": "^7.2.0" - }, - "bin": { - "chrome-remote-interface": "bin/client.js" - } - }, - "node_modules/chrome-remote-interface/node_modules/commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", - "dev": true - }, - "node_modules/chrome-remote-interface/node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "dev": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/chrome-trace-event": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", @@ -6188,18 +6139,6 @@ "node": "^16.0.0 || ^18.0.0 || >=20.0.0" } }, - "node_modules/cypress-file-upload": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/cypress-file-upload/-/cypress-file-upload-5.0.8.tgz", - "integrity": "sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g==", - "dev": true, - "engines": { - "node": ">=8.2.1" - }, - "peerDependencies": { - "cypress": ">3.0.0" - } - }, "node_modules/cypress/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -9220,12 +9159,6 @@ "node": ">=8" } }, - "node_modules/inspect-custom-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/inspect-custom-symbol/-/inspect-custom-symbol-1.1.1.tgz", - "integrity": "sha512-GOucsp9EcdlLdhPUyOTvQDnbFJtp2WBWZV1Jqe+mVnkJQBL3w96+fB84C+JL+EKXOspMdB0eMDQPDp5w9fkfZA==", - "dev": true - }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -10221,18 +10154,6 @@ "node": ">=4.0" } }, - "node_modules/just-flatten-it": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/just-flatten-it/-/just-flatten-it-2.2.1.tgz", - "integrity": "sha512-VwvlzikphspzZL38LiZpoBsFGQy6MnmXYekBeZA8lSNwgSC87zA3a93bCZKkDuOM+djMZhfjd3lXAZyxficKCg==", - "dev": true - }, - "node_modules/just-zip-it": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/just-zip-it/-/just-zip-it-2.3.1.tgz", - "integrity": "sha512-h8Y3DAVTZRP3Weq7btWYfkYHQGhxiuKzfOO7Ec+x8XaDcBvbOsC2jIdezC6tEzbt+A4fTJTREnj3gF5DyMkFfw==", - "dev": true - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -13982,18 +13903,6 @@ "node": ">=8" } }, - "node_modules/shell-escape-tag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/shell-escape-tag/-/shell-escape-tag-2.0.2.tgz", - "integrity": "sha512-kqmtJG6VzTahZl8Y3384ldskA9rzoEMdXLoMEBAq9334/UDdmfWl3OtmrGJPlVcyXvcSy3poDKka57gMxskMPw==", - "dev": true, - "dependencies": { - "any-shell-escape": "^0.1.1", - "inspect-custom-symbol": "^1.1.1", - "just-flatten-it": "^2.1.0", - "just-zip-it": "^2.1.0" - } - }, "node_modules/shell-quote": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", diff --git a/package.json b/package.json index 18f0102e..d4ab39c0 100644 --- a/package.json +++ b/package.json @@ -34,12 +34,10 @@ "@ls-lint/ls-lint": "^2.2.3", "@trivago/prettier-plugin-sort-imports": "^5.2.0", "babel-loader": "^9.2.1", - "chrome-remote-interface": "^0.33.2", "clean-webpack-plugin": "^4.0.0", "copy-webpack-plugin": "^12.0.2", "css-loader": "^7.1.2", "cypress": "^13.17.0", - "cypress-file-upload": "^5.0.8", "eslint": "~9.17.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-lingui": "^0.9.0", @@ -53,7 +51,6 @@ "prettier": "^3.4.2", "sass": "1.83.0", "sass-loader": "^16.0.4", - "shell-escape-tag": "^2.0.2", "source-map-loader": "^5.0.0", "style-loader": "^4.0.0", "stylelint": "^16.12.0", diff --git a/src/components/language-switcher.tsx b/src/components/language-switcher.tsx index 99a62ae4..9a15eec0 100644 --- a/src/components/language-switcher.tsx +++ b/src/components/language-switcher.tsx @@ -18,8 +18,8 @@ export function LanguageSwitcher(_props) { items={[ {window.localStorage.override_l10n - ? t`{currentLanguage} (current)` - : t`{currentLanguage} (browser default)`} + ? t`${currentLanguage} (current)` + : t`${currentLanguage} (browser default)`} , , ...availableLanguages.map((lang) => (