diff --git a/cypress/e2e/awx/access/users.cy.ts b/cypress/e2e/awx/access/users.cy.ts index b72ec09964..1eff4cce34 100644 --- a/cypress/e2e/awx/access/users.cy.ts +++ b/cypress/e2e/awx/access/users.cy.ts @@ -112,7 +112,9 @@ describe('Users Delete Actions', () => { it('deletes a user from the users list row item', () => { cy.navigateTo('awx', 'users'); - cy.clickTableRowKebabAction(user.username, 'delete-user'); + cy.clickTableRowAction('username', user.username, 'delete-user', { + inKebab: true, + }); cy.get('#confirm').click(); cy.clickButton(/^Delete user/); cy.contains(/^Success$/); diff --git a/cypress/e2e/awx/administration/credentialTypes.cy.ts b/cypress/e2e/awx/administration/credentialTypes.cy.ts index 4e8e262121..2f98ff5af2 100644 --- a/cypress/e2e/awx/administration/credentialTypes.cy.ts +++ b/cypress/e2e/awx/administration/credentialTypes.cy.ts @@ -220,7 +220,10 @@ describe('Credential Types', () => { }); cy.navigateTo('awx', 'credential-types'); cy.filterTableByMultiSelect('name', [editedCredentialTypeName]); - cy.clickTableRowKebabAction(`${editedCredentialTypeName}`, 'delete-credential-type', false); + cy.clickTableRowAction('name', editedCredentialTypeName, 'delete-credential-type', { + disableFilter: true, + inKebab: true, + }); cy.get('#confirm').click(); cy.intercept('DELETE', awxAPI`/credential_types/${credType1.id.toString()}/`).as( 'deleteCredType' @@ -285,7 +288,10 @@ describe('Credential Types', () => { it('can delete a credential type from the list row action', () => { cy.navigateTo('awx', 'credential-types'); cy.filterTableByMultiSelect('name', [credType1.name]); - cy.clickTableRowKebabAction(credType1.name, 'delete-credential-type', false); + cy.clickTableRowAction('name', credType1.name, 'delete-credential-type', { + disableFilter: true, + inKebab: true, + }); cy.get('#confirm').click(); cy.clickButton(/^Delete credential type/); cy.contains(/^Success$/); diff --git a/cypress/e2e/awx/administration/instanceGroups.cy.ts b/cypress/e2e/awx/administration/instanceGroups.cy.ts index 79f167dbaf..a5248db06c 100644 --- a/cypress/e2e/awx/administration/instanceGroups.cy.ts +++ b/cypress/e2e/awx/administration/instanceGroups.cy.ts @@ -52,7 +52,7 @@ describe(`Instance Groups`, () => { cy.navigateTo('awx', 'instance-groups'); cy.verifyPageTitle('Instance Groups'); cy.clickButton(/^Create group$/); - cy.clickLink(`Create instance group`); + cy.clickButton(`Create instance group`); cy.get('[data-cy="name"]').type(name); cy.get('[data-cy="policy-instance-minimum"]').clear(); cy.get('[data-cy="policy-instance-minimum"]').type('1'); @@ -100,7 +100,10 @@ describe(`Instance Groups`, () => { cy.navigateTo('awx', 'instance-groups'); cy.verifyPageTitle('Instance Groups'); cy.filterTableBySingleSelect('name', instanceGroup.name); - cy.clickTableRowKebabAction(instanceGroup.name, `edit-instance-group`, false); + cy.clickTableRowAction('name', instanceGroup.name, `edit-instance-group`, { + inKebab: false, + disableFilter: true, + }); cy.get('[data-cy="name"]').clear(); cy.get('[data-cy="name"]').type(`${instanceGroup.name}- edited`); cy.get('[data-cy="policy-instance-minimum"]').clear(); @@ -237,7 +240,7 @@ describe(`Instance Groups`, () => { cy.navigateTo('awx', 'instance-groups'); cy.verifyPageTitle('Instance Groups'); cy.clickButton(/^Create group$/); - cy.clickLink(`Create container group`); + cy.clickButton(/^Create container group$/); cy.get('[data-cy="name"]').type(name); cy.get('[data-cy="max-concurrent-jobs"]').clear(); cy.get('[data-cy="max-concurrent-jobs"]').type('3'); @@ -1008,7 +1011,10 @@ describe(`Instance Groups`, () => { cy.clickTab(/^Jobs$/, true); cy.filterTableBySingleSelect('name', job_template.name); cy.intercept('DELETE', awxAPI`/jobs/*/`).as('deleted'); - cy.clickTableRowKebabAction(job_template.name, 'delete-job', false); + cy.clickTableRowAction('name', job_template.name, 'delete-job', { + inKebab: true, + disableFilter: true, + }); cy.clickModalConfirmCheckbox(); cy.clickModalButton('Delete job'); cy.assertModalSuccess(); diff --git a/cypress/e2e/awx/administration/wfApprovalsList.cy.ts b/cypress/e2e/awx/administration/wfApprovalsList.cy.ts index 18b15e6b4f..86852dc571 100644 --- a/cypress/e2e/awx/administration/wfApprovalsList.cy.ts +++ b/cypress/e2e/awx/administration/wfApprovalsList.cy.ts @@ -148,6 +148,7 @@ describe('Workflow Approvals Tests', () => { cy.getByDataCy('actions-column-cell').within(() => { cy.clickKebabAction('actions-dropdown', 'delete-workflow-approval'); }); + cy.actionsWFApprovalConfirmModal('delete'); cy.wait('@deleteWFA') .its('response') @@ -456,12 +457,9 @@ describe('Workflow Approvals Tests', () => { cy.get('tbody').find('tr').should('have.length', 3); cy.getByDataCy('select-all').click(); cy.getBy('[data-ouia-component-id="page-toolbar"]').within(() => { - cy.getByDataCy('actions-dropdown') - .click() - .then(() => { - cy.getByDataCy('delete').click(); - }); + cy.getByDataCy('actions-dropdown').click(); }); + cy.getByDataCy('delete').click(); cy.getModal().within(() => { cy.get('[data-ouia-component-id="confirm"]').click(); cy.get('[data-ouia-component-id="submit"]').click(); @@ -558,12 +556,9 @@ describe('Workflow Approvals Tests', () => { cy.getByDataCy('checkbox-column-cell').click(); }); cy.get('[data-ouia-component-id="page-toolbar"]').within(() => { - cy.getByDataCy('actions-dropdown') - .click() - .then(() => { - cy.get('[data-cy="delete"]').click(); - }); + cy.getByDataCy('actions-dropdown').click(); }); + cy.get('[data-cy="delete"]').click(); cy.getModal().within(() => { cy.get('[data-cy="alert-toaster"]').should( 'contain', diff --git a/cypress/e2e/awx/resources/credentials.cy.ts b/cypress/e2e/awx/resources/credentials.cy.ts index ea9bd9b0e4..6cf6a22098 100644 --- a/cypress/e2e/awx/resources/credentials.cy.ts +++ b/cypress/e2e/awx/resources/credentials.cy.ts @@ -66,7 +66,10 @@ describe('Credentials', () => { it('can delete machine credential from the list row action', () => { cy.navigateTo('awx', 'credentials'); cy.filterTableByMultiSelect('name', [credential.name]); - cy.clickTableRowKebabAction(credential.name, 'delete-credential', false); + cy.clickTableRowAction('name', credential.name, 'delete-credential', { + disableFilter: true, + inKebab: true, + }); cy.get('#confirm').click(); cy.intercept('DELETE', awxAPI`/credentials/${credential.id.toString()}/`).as('deleted'); cy.clickButton(/^Delete credential/); diff --git a/cypress/e2e/awx/resources/executionEnvironments.cy.ts b/cypress/e2e/awx/resources/executionEnvironments.cy.ts index ae4f6b06f7..c7ea88e9f9 100644 --- a/cypress/e2e/awx/resources/executionEnvironments.cy.ts +++ b/cypress/e2e/awx/resources/executionEnvironments.cy.ts @@ -83,7 +83,10 @@ describe('Execution Environments', () => { cy.clickTab(/^Back to Execution Environments$/, true); cy.verifyPageTitle('Execution Environments'); cy.filterTableBySingleSelect('name', execEnvName); - cy.clickTableRowKebabAction(execEnvName, 'delete-execution-environment', false); + cy.clickTableRowAction('name', execEnvName, 'delete-execution-environment', { + inKebab: true, + disableFilter: true, + }); cy.clickModalConfirmCheckbox(); cy.intercept('DELETE', awxAPI`/execution_environments/*/`).as('deleteEE'); cy.clickModalButton('Delete execution environments'); @@ -130,7 +133,10 @@ describe('Execution Environments', () => { cy.verifyPageTitle(awxOrganization.name); cy.clickTab(/^Execution Environments$/, true); cy.filterTableBySingleSelect('name', execEnvName); - cy.clickTableRowKebabAction(execEnvName, 'delete-execution-environment', false); + cy.clickTableRowAction('name', execEnvName, 'delete-execution-environment', { + inKebab: true, + disableFilter: true, + }); cy.clickModalConfirmCheckbox(); cy.intercept('DELETE', awxAPI`/execution_environments/*/`).as('deleteEE'); cy.clickModalButton('Delete execution environments'); @@ -166,17 +172,10 @@ describe('Execution Environments', () => { cy.hasDetail('Name', execEnvName); cy.hasDetail('Image', image); cy.hasDetail('Organization', awxOrganization.name); - cy.getByDataCy('actions-dropdown') - .click() - .then(() => { - cy.get('[data-cy="delete-execution-environment"]').should( - 'have.attr', - 'aria-disabled', - 'true' - ); - cy.logout(); - cy.login(); - }); + cy.getByDataCy('actions-dropdown').click(); + cy.get('#delete-execution-environment').should('have.attr', 'aria-disabled', 'true'); + cy.logout(); + cy.login(); }); }); @@ -363,7 +362,10 @@ describe('Execution Environments', () => { cy.getByDataCy('image').should('contain', image); cy.clickTab(/^Templates$/, true); cy.filterTableBySingleSelect('name', jtName); - cy.clickTableRowKebabAction(jtName, 'delete-template', false); + cy.clickTableRowAction('name', jtName, 'delete-template', { + inKebab: true, + disableFilter: true, + }); cy.clickModalConfirmCheckbox(); cy.intercept('DELETE', awxAPI`/job_templates/*/`).as('deleteJT'); cy.clickModalButton('Delete template'); diff --git a/cypress/e2e/awx/resources/inventories.cy.ts b/cypress/e2e/awx/resources/inventories.cy.ts index 15a0f331ca..79f18990b8 100644 --- a/cypress/e2e/awx/resources/inventories.cy.ts +++ b/cypress/e2e/awx/resources/inventories.cy.ts @@ -57,7 +57,7 @@ describe('Inventories Tests', () => { const inventoryName = 'E2E Inventory ' + randomString(4); cy.navigateTo('awx', 'inventories'); cy.clickButton(/^Create inventory$/); - cy.clickLink(/^Create inventory$/); + cy.get('#create-inventory').click(); //Assert that user is on the form view to create an inventory cy.get('[data-cy="name"]').type(inventoryName); cy.singleSelectByDataCy('organization', organization.name); @@ -122,7 +122,10 @@ describe('Inventories Tests', () => { //Refactor this test to match the updated test case and improve the assertions cy.navigateTo('awx', 'inventories'); //Add assertion to verify the user is on the inventories list view cy.filterTableBySingleSelect('name', inventory.name); - cy.clickTableRowKebabAction(inventory.name, 'copy-inventory', false); + cy.clickTableRowAction('name', inventory.name, 'copy-inventory', { + disableFilter: true, + inKebab: true, + }); cy.hasAlert(`${inventory.name.toString()} copied`); //Assert the presence of the original and the copy by performing a search on the list of inventories }); @@ -130,7 +133,10 @@ describe('Inventories Tests', () => { it('can delete an inventory from the inventory list row item', () => { cy.navigateTo('awx', 'inventories'); cy.filterTableBySingleSelect('name', inventory.name); - cy.clickTableRowKebabAction(inventory.name, 'delete-inventory', false); + cy.clickTableRowAction('name', inventory.name, 'delete-inventory', { + disableFilter: true, + inKebab: true, + }); //Add assertion to show the presence of the expected inventory cy.get('#confirm').click(); cy.clickButton(/^Delete inventory/); diff --git a/cypress/e2e/awx/resources/inventoriesConstructed.cy.ts b/cypress/e2e/awx/resources/inventoriesConstructed.cy.ts index af91a96ef4..9d9d0b315d 100644 --- a/cypress/e2e/awx/resources/inventoriesConstructed.cy.ts +++ b/cypress/e2e/awx/resources/inventoriesConstructed.cy.ts @@ -60,10 +60,8 @@ describe('Constructed Inventories CRUD Tests', () => { const verbosityValue = generateRandom(0, 2); cy.navigateTo('awx', 'inventories'); - cy.getByDataCy('create-inventory').click(); - cy.get('.pf-v5-c-dropdown__menu').within(() => { - cy.get('[data-cy="create-constructed-inventory"]').click(); - }); + cy.clickButton(/^Create inventory$/); + cy.clickButton(/^Create constructed inventory$/); cy.getByDataCy('name').type(constInvName); cy.getByDataCy('description').type(`Description of "${constInvName}" typed by Cypress`); cy.intercept({ diff --git a/cypress/e2e/awx/resources/inventoryGroup.cy.ts b/cypress/e2e/awx/resources/inventoryGroup.cy.ts index 2c35498e49..b47cd8333e 100644 --- a/cypress/e2e/awx/resources/inventoryGroup.cy.ts +++ b/cypress/e2e/awx/resources/inventoryGroup.cy.ts @@ -98,7 +98,10 @@ describe('Inventory Groups', () => { cy.getByDataCy('name-column-cell').should('contain', host.name); cy.clickTab(/^Groups$/, true); cy.filterTableByMultiSelect('name', [group.name]); - cy.clickTableRowKebabAction(group.name, 'edit-group', false); + cy.clickTableRowAction('name', group.name, 'edit-group', { + inKebab: false, + disableFilter: true, + }); cy.verifyPageTitle('Edit group'); cy.get('[data-cy="name-form-group"]').type('-changed'); cy.get('[data-cy="Submit"]').click(); @@ -118,7 +121,7 @@ describe('Inventory Groups', () => { cy.clickTableRowLink('name', inventory.name, { disableFilter: true }); cy.verifyPageTitle(inventory.name); cy.clickTab(/^Groups$/, true); - cy.clickKebabAction('actions-dropdown', 'run-command'); + cy.clickButton(/^Run Command$/); cy.selectDropdownOptionByResourceName('module-name', 'shell'); cy.getByDataCy('module-args-form-group').type('argument'); cy.selectDropdownOptionByResourceName('verbosity', '1 (Verbose)'); diff --git a/cypress/e2e/awx/resources/jobTemplates.cy.ts b/cypress/e2e/awx/resources/jobTemplates.cy.ts index b20e621a67..82b56969da 100644 --- a/cypress/e2e/awx/resources/jobTemplates.cy.ts +++ b/cypress/e2e/awx/resources/jobTemplates.cy.ts @@ -142,9 +142,7 @@ describe.skip('Job Templates Tests', function () { }); cy.get('[data-ouia-component-type="PF5/ModalContent"]').within(() => { cy.filterTableBySingleSelect('name', executionEnvironmentName); - cy.get('[data-ouia-component-id="simple-table"] tbody').within(() => { - cy.get('[data-cy="checkbox-column-cell"] input').click(); - }); + cy.selectTableRowByCheckbox('name', executionEnvironmentName, { disableFilter: true }); cy.clickButton(/^Confirm/); }); cy.clickButton(/^Next/); @@ -546,9 +544,9 @@ describe.skip('Job Templates Tests', function () { cy.intercept('POST', awxAPI`/job_templates/${jobTemplate.id.toString()}/copy/`).as( 'copyTemplate' ); - cy.getByDataCy('actions-column-cell').within(() => { - cy.getByDataCy('actions-dropdown').click(); - cy.getByDataCy('copy-template').click(); + cy.clickTableRowAction('name', jobTemplate.name, 'copy-template', { + inKebab: true, + disableFilter: true, }); cy.wait('@copyTemplate') .its('response.body.name') @@ -630,10 +628,7 @@ describe.skip('Job Templates Tests', function () { it('can delete a job template from the list line item', function () { cy.navigateTo('awx', 'templates'); cy.filterTableBySingleSelect('name', jobTemplate.name); - cy.getByDataCy('actions-column-cell').within(() => { - cy.getByDataCy('actions-dropdown').click(); - cy.getByDataCy('delete-template').click(); - }); + cy.clickTableRowKebabAction(jobTemplate.name, 'delete-template'); cy.clickModalConfirmCheckbox(); cy.intercept('DELETE', awxAPI`/job_templates/${jobTemplate.id.toString()}/`).as('deleteJT'); cy.clickModalButton('Delete template'); diff --git a/cypress/e2e/awx/resources/projects/project-details.cy.ts b/cypress/e2e/awx/resources/projects/project-details.cy.ts index 15e715b6fd..8cff71b680 100644 --- a/cypress/e2e/awx/resources/projects/project-details.cy.ts +++ b/cypress/e2e/awx/resources/projects/project-details.cy.ts @@ -234,7 +234,10 @@ describe('Projects', () => { it('can delete a schedule from the schedules list row', () => { cy.filterTableBySingleSelect('name', schedule.name); - cy.clickTableRowKebabAction(schedule.name, 'delete-schedule', false); + cy.clickTableRowAction('name', schedule.name, 'delete-schedule', { + disableFilter: true, + inKebab: true, + }); cy.getModal().then(() => { cy.get('#confirm').click(); cy.intercept('DELETE', awxAPI`/schedules/${schedule.id.toString()}/`).as('deleted'); diff --git a/cypress/e2e/awx/resources/sharedTemplateSurvey.ts b/cypress/e2e/awx/resources/sharedTemplateSurvey.ts index 16fafc4ceb..45c97af8c5 100644 --- a/cypress/e2e/awx/resources/sharedTemplateSurvey.ts +++ b/cypress/e2e/awx/resources/sharedTemplateSurvey.ts @@ -75,8 +75,10 @@ export class ReusableTemplateSurveyTestSuite { cy.contains(question.question_name); cy.contains(question.default); cy.contains('text'); - cy.getByDataCy('actions-dropdown').click(); - cy.contains('Delete question').click(); + }); + cy.clickTableRowAction('name', question.question_name, 'delete-question', { + inKebab: true, + disableFilter: true, }); cy.clickModalConfirmCheckbox(); cy.intercept( diff --git a/cypress/e2e/awx/views/jobs.cy.ts b/cypress/e2e/awx/views/jobs.cy.ts index a98bc2af3c..32deeded44 100644 --- a/cypress/e2e/awx/views/jobs.cy.ts +++ b/cypress/e2e/awx/views/jobs.cy.ts @@ -80,10 +80,8 @@ describe('Jobs', () => { it('can render the toolbar and row actions', () => { cy.navigateTo('awx', 'jobs'); cy.get('.pf-v5-c-toolbar__group button.toggle-kebab').click(); - cy.get('.pf-v5-c-dropdown__menu').within(() => { - cy.contains(/^Delete jobs$/).should('exist'); - cy.contains(/^Cancel jobs$/).should('exist'); - }); + cy.contains(/^Delete jobs$/).should('exist'); + cy.contains(/^Cancel jobs$/).should('exist'); cy.filterTableByMultiSelect('id', [job.id ? job.id.toString() : '']); const jobName = job.name ? job.name : ''; cy.contains('td', jobName) @@ -91,9 +89,9 @@ describe('Jobs', () => { .within(() => { // Relaunch job cy.get('#relaunch-job').should('exist'); - cy.get('.pf-v5-c-dropdown__toggle').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete job$/).should('exist'); + cy.getByDataCy('actions-dropdown').click(); }); + cy.contains('#delete-job', /^Delete job$/).should('exist'); cy.clearAllFilters(); }); diff --git a/cypress/e2e/eda/Decision-Environments/decision-env-list.cy.ts b/cypress/e2e/eda/Decision-Environments/decision-env-list.cy.ts index 02d5239aa1..eb31395cf4 100644 --- a/cypress/e2e/eda/Decision-Environments/decision-env-list.cy.ts +++ b/cypress/e2e/eda/Decision-Environments/decision-env-list.cy.ts @@ -49,7 +49,7 @@ describe('EDA Decision Environment List', () => { cy.setTableView('table'); cy.filterTableByTextFilter('name', edaDE.name, { disableFilterSelection: true }); cy.setTableView('card'); - cy.clickListCardKebabAction(edaDE.id, edaDE.name, 'delete-decision-environment'); + cy.clickListCardKebabAction(edaDE.id, 'delete-decision-environment'); cy.get('#confirm').click(); cy.clickButton(/^Delete decision environment/); cy.contains(/^Success$/); diff --git a/cypress/e2e/eda/Rulebook-Activations/rulebook-activations-list.cy.ts b/cypress/e2e/eda/Rulebook-Activations/rulebook-activations-list.cy.ts index 3615852694..1dc5d3670b 100644 --- a/cypress/e2e/eda/Rulebook-Activations/rulebook-activations-list.cy.ts +++ b/cypress/e2e/eda/Rulebook-Activations/rulebook-activations-list.cy.ts @@ -97,8 +97,9 @@ describe('EDA rulebook activations- Create, Edit, Delete', () => { it('can delete a single Rulebook Activation from the line item on the list view', () => { cy.navigateTo('eda', 'rulebook-activations'); - cy.edaRuleBookActivationCheckbox(edaRBA1.name).within(() => { - cy.clickPageAction('delete-rulebook-activation'); + cy.clickTableRowAction('name', edaRBA1.name, 'delete-rulebook-activation', { + disableFilter: true, + inKebab: true, }); cy.get('div[role="dialog"]').within(() => { cy.get('.pf-v5-c-check__label').should( diff --git a/cypress/e2e/hub/execution-environments.cy.ts b/cypress/e2e/hub/execution-environments.cy.ts index 5192e0874a..0dc10f4215 100644 --- a/cypress/e2e/hub/execution-environments.cy.ts +++ b/cypress/e2e/hub/execution-environments.cy.ts @@ -72,12 +72,9 @@ describe('Execution Environments', () => { cy.get('tbody').find('tr').should('have.length', 1); cy.get('tbody').within(() => { cy.getByDataCy('container-repository-name-column-cell').should('contain', eeName); - cy.get('[data-cy="actions-dropdown"]') - .click() - .then(() => { - cy.get(`[data-cy="delete-execution-environment"]`).click(); - }); + cy.get('[data-cy="actions-dropdown"]').click(); }); + cy.get(`[data-cy="delete-execution-environment"]`).click(); cy.get('[data-ouia-component-id="Permanently delete execution environments"]').within( () => { cy.get('[data-ouia-component-id="confirm"]').click(); diff --git a/cypress/e2e/hub/hub-roles.cy.ts b/cypress/e2e/hub/hub-roles.cy.ts index 802803ecfe..61566391f8 100644 --- a/cypress/e2e/hub/hub-roles.cy.ts +++ b/cypress/e2e/hub/hub-roles.cy.ts @@ -85,7 +85,7 @@ describe('Hub roles', () => { it('delete a role from the list row action', () => { cy.createHubRole().then((createdRole: Role) => { cy.navigateTo('hub', 'roles'); - cy.clickTableRowKebabAction(createdRole.name, 'delete-role', true); + cy.clickTableRowAction('name', createdRole.name, 'delete-role', { inKebab: true }); cy.get('#confirm').click(); cy.clickButton(/^Delete role/); cy.contains(/^Success$/); diff --git a/cypress/e2e/hub/remote-registries.cy.ts b/cypress/e2e/hub/remote-registries.cy.ts index eef27a2fca..596b6967c0 100644 --- a/cypress/e2e/hub/remote-registries.cy.ts +++ b/cypress/e2e/hub/remote-registries.cy.ts @@ -59,8 +59,10 @@ describe('Remote Registry', () => { 'contain', RemoteRegistry.initialSyncStatus ); - cy.get('[data-cy="actions-column-cell"]').click(); - cy.get('[data-cy="sync-remote-registry"]').click({ force: true }); + cy.clickTableRowAction('name', remoteRegistryName, 'sync-remote-registry', { + disableFilter: true, + inKebab: true, + }); cy.get('[data-cy="sync-status-column-cell"]').should('contain', RemoteRegistry.syncStatus); cy.deleteRemoteRegistry(remoteRegistry.id); }); @@ -73,13 +75,15 @@ describe('Remote Registry', () => { cy.navigateTo('hub', RemoteRegistry.url); cy.url().should('include', 'remote-registries'); cy.filterTableBySingleText(remoteRegistry.name); - cy.get('[data-cy="actions-column-cell"]').click(); - cy.get('[data-cy="index-execution-environments"]') - .should('be.visible') - .click({ force: true }); + cy.clickTableRowAction('name', remoteRegistry.name, 'index-execution-environments', { + disableFilter: true, + inKebab: true, + }); cy.hasAlert(`Indexing remote registry ${remoteRegistry.name}`); - cy.get('[data-cy="actions-column-cell"]').click(); - cy.get('[data-cy="delete-remote-registry"]').click({ force: true }); + cy.clickTableRowAction('name', remoteRegistry.name, 'delete-remote-registry', { + disableFilter: true, + inKebab: true, + }); cy.get('#confirm').click(); cy.clickButton(/^Delete remote registries/); cy.clickButton(/^Close$/); @@ -101,8 +105,10 @@ describe('Remote Registry', () => { cy.contains('Remote registries').click(); cy.url().should('include', RemoteRegistry.url); cy.filterTableBySingleText(remoteRegistryName); - cy.get('[data-cy="actions-column-cell"]').click(); - cy.get('[data-cy="delete-remote-registry"]').click({ force: true }); + cy.clickTableRowAction('name', remoteRegistryName, 'delete-remote-registry', { + disableFilter: true, + inKebab: true, + }); cy.get('#confirm').click(); cy.clickButton(/^Delete remote registries/); cy.clickButton(/^Close$/); diff --git a/cypress/e2e/hub/remotes.cy.ts b/cypress/e2e/hub/remotes.cy.ts index ae58e94908..37f3330fbe 100644 --- a/cypress/e2e/hub/remotes.cy.ts +++ b/cypress/e2e/hub/remotes.cy.ts @@ -64,8 +64,10 @@ describe('Remotes', () => { cy.contains('Remotes').click(); cy.url().should('include', Remotes.url); cy.filterTableBySingleText(remoteName); - cy.get('[data-cy="actions-column-cell"]').click(); - cy.get('[data-cy="delete-remote"]').click({ force: true }); + cy.clickTableRowAction('remote-name', remoteName, 'delete-remote', { + disableFilter: true, + inKebab: true, + }); cy.get('#confirm').click(); cy.clickButton(/^Delete remote/); cy.contains(/^Success$/); @@ -95,8 +97,10 @@ describe('Remotes', () => { cy.wait('@remote').then(() => { cy.contains('Remotes').click(); cy.filterTableBySingleText(remoteName); - cy.get('[data-cy="actions-column-cell"]').click(); - cy.get('[data-cy="delete-remote"]').click({ force: true }); + cy.clickTableRowAction('remote-name', remoteName, 'delete-remote', { + disableFilter: true, + inKebab: true, + }); cy.get('#confirm').click(); cy.clickButton(/^Delete remote/); cy.contains(/^Success$/); diff --git a/cypress/e2e/hub/tasks.cy.ts b/cypress/e2e/hub/tasks.cy.ts index fe13b7683e..a4c35a95b8 100644 --- a/cypress/e2e/hub/tasks.cy.ts +++ b/cypress/e2e/hub/tasks.cy.ts @@ -19,7 +19,10 @@ describe('Tasks', () => { }).then((repository) => { cy.navigateTo('hub', Repositories.url); cy.filterTableBySingleText(repository.name); - cy.clickTableRowKebabAction(repository.name, 'sync-repository', false); + cy.clickTableRowAction('name', repository.name, 'sync-repository', { + disableFilter: true, + inKebab: true, + }); cy.get('[data-cy="Submit"]').click(); cy.hasAlert(`Sync started for repository "${repository.name}"`).should('be.visible'); cy.navigateTo('hub', Tasks.url); diff --git a/cypress/support/awx-commands.ts b/cypress/support/awx-commands.ts index aa17c43d83..936f02c4e1 100644 --- a/cypress/support/awx-commands.ts +++ b/cypress/support/awx-commands.ts @@ -425,7 +425,12 @@ Cypress.Commands.add('hasTooltip', (label: string | RegExp) => { Cypress.Commands.add('clickToolbarKebabAction', (dataCy: string) => { cy.getBy('[data-ouia-component-id="page-toolbar"]').within(() => { cy.getByDataCy('actions-dropdown').click(); - cy.getByDataCy(dataCy).click(); + cy.document() + .its('body') + .find('.pf-v5-c-menu__content') + .within(() => { + cy.getByDataCy(dataCy).click(); + }); }); }); @@ -475,18 +480,18 @@ Cypress.Commands.add( }); } ); -Cypress.Commands.add( - 'clickListCardKebabAction', - (id: number, name: string | RegExp, dataCyLabel: string | RegExp) => { - cy.get(`[data-ouia-component-id="${id}"]`).within(() => { - cy.get('[data-cy*="actions-dropdown"]') - .click() - .then(() => { - cy.get(`[data-cy=${dataCyLabel}]`).click(); - }); - }); - } -); + +Cypress.Commands.add('clickListCardKebabAction', (id: number, dataCyLabel: string) => { + cy.get(`[data-ouia-component-id="${id}"]`).within(() => { + cy.get('[data-cy*="actions-dropdown"]').click(); + cy.document() + .its('body') + .find('.pf-v5-c-menu__content') + .within(() => { + cy.getByDataCy(dataCyLabel).click(); + }); + }); +}); Cypress.Commands.add( 'clickTableRowPinnedAction', diff --git a/cypress/support/commands.d.ts b/cypress/support/commands.d.ts index 11edaa8bb2..714193ed5b 100644 --- a/cypress/support/commands.d.ts +++ b/cypress/support/commands.d.ts @@ -547,15 +547,10 @@ declare global { /** * Finds a list card containing text and clicks action specified by label. - * @param name - * @param label - * @param filter + * @param id + * @param dataCyLabel */ - clickListCardKebabAction( - id: number, - name: string | RegExp, - dataCyLabel: string | RegExp - ): Chainable; + clickListCardKebabAction(id: number, dataCyLabel: string): Chainable; /** Finds a table row containing text and clicks action specified by label. */ clickTableRowPinnedAction( diff --git a/cypress/support/table-commands.ts b/cypress/support/table-commands.ts index af2e3f17cb..bdaf21fd1a 100644 --- a/cypress/support/table-commands.ts +++ b/cypress/support/table-commands.ts @@ -137,7 +137,12 @@ Cypress.Commands.add( Cypress.Commands.add('clickKebabAction', (kebabDataCy: string, actionDataCy: string) => { cy.getByDataCy(kebabDataCy).click(); - cy.getByDataCy(actionDataCy).click(); + cy.document() + .its('body') + .find(`[data-cy="${actionDataCy}"]`) + .within(() => { + cy.get('button').click(); + }); }); Cypress.Commands.add( diff --git a/framework/PageActions/PageActionDropdown.tsx b/framework/PageActions/PageActionDropdown.tsx index 27be75bbb2..54d6ef0a12 100644 --- a/framework/PageActions/PageActionDropdown.tsx +++ b/framework/PageActions/PageActionDropdown.tsx @@ -1,16 +1,19 @@ -import { ButtonVariant, Tooltip } from '@patternfly/react-core'; import { + Button, + ButtonVariant, + Divider, Dropdown, DropdownItem, - DropdownPosition, - DropdownSeparator, - DropdownToggle, - KebabToggle, -} from '@patternfly/react-core/deprecated'; -import { CircleIcon } from '@patternfly/react-icons'; + DropdownList, + DropdownPopperProps, + Icon, + MenuToggle, + MenuToggleElement, + Tooltip, +} from '@patternfly/react-core'; +import { CircleIcon, EllipsisVIcon, CaretDownIcon } from '@patternfly/react-icons'; import { ComponentClass, FunctionComponent, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { Link } from 'react-router-dom'; import styled from 'styled-components'; import { PFColorE, getPatternflyColor } from '../components/pfcolors'; import { getID } from '../hooks/useID'; @@ -40,7 +43,7 @@ interface PageActionDropdownProps { isDisabled?: string | undefined; label?: string; onOpen?: (label: string, open: boolean) => void; - position?: DropdownPosition; + position?: DropdownPopperProps['position']; selectedItem?: T; selectedItems?: T[]; tooltip?: string; @@ -97,64 +100,15 @@ export function PageActionDropdown(props: PageActionDropdownPr const id = getID(props.label ?? 'actions-dropdown'); if (actions.length === 0) return <>; - const Icon = icon; const isPrimary = variant === ButtonVariant.primary || (hasBulkActions && !!selectedItems?.length); /** Turn primary button to secondary if there are items selected */ const isSecondary = variant === ButtonVariant.primary && !hasBulkActions && !!selectedItems?.length; - const Toggle = - label || Icon ? ( - setDropdownOpen(!dropdownOpen)} - toggleVariant={isSecondary ? 'secondary' : isPrimary ? 'primary' : undefined} - toggleIndicator={Icon && iconOnly ? null : undefined} - style={isPrimary && !label ? { color: 'var(--pf-v5-global--Color--light-100)' } : {}} - icon={Icon ? : undefined} - data-cy={id} - > - {iconOnly ? undefined : label} - - ) : ( - setDropdownOpen(!dropdownOpen)} - toggleVariant={isPrimary ? 'primary' : undefined} - style={isPrimary && !label ? { color: 'var(--pf-v5-global--Color--light-100)' } : {}} - data-cy={id} - /> - ); - const dropdown = ( - setDropdownOpen(false)} - toggle={Toggle} - isOpen={dropdownOpen} - isPlain={!label || iconOnly} - dropdownItems={actions.map((action, index) => ( - - ))} - position={position} - // ZIndex 400 is needed for PF table stick headers - style={{ zIndex: dropdownOpen ? 400 : undefined, padding: 0 }} - className={ - props.variant === ButtonVariant.control ? 'pf-v5-c-button pf-m-control' : undefined - } - /> - ); - let tooltipContent; + const isKebab = Boolean(!label && !icon); + const CustomIcon = icon; + let tooltipContent; if (isDisabled) { tooltipContent = isDisabled; } else if (tooltip) { @@ -165,9 +119,91 @@ export function PageActionDropdown(props: PageActionDropdownPr tooltipContent = undefined; } + const dropdownMenuLabel: string | JSX.Element | undefined = + iconOnly && CustomIcon ? ( + + + + ) : ( + label + ); + + const disabledMenuToggle = ( + + ); + return ( - {dropdown} + {isDisabled ? ( + disabledMenuToggle + ) : ( + setDropdownOpen(false)} + onOpenChange={(isOpen) => setDropdownOpen(isOpen)} + popperProps={{ + appendTo: () => document.body, + preventOverflow: true, + enableFlip: true, + position: position, + }} + toggle={(toggleRef: React.Ref) => ( + setDropdownOpen(!dropdownOpen)} + isExpanded={dropdownOpen} + style={isPrimary && !label ? { color: 'var(--pf-v5-global--Color--light-100)' } : {}} + icon={ + CustomIcon ? ( + + + + ) : undefined + } + > + {dropdownMenuLabel ?? } + + )} + > + + {actions.map((action, index) => ( + + ))} + + + )} ); } @@ -187,8 +223,8 @@ function PageDropdownActionItem(props: { switch (action.type) { case PageActionType.Button: { - let Icon: ComponentClass | FunctionComponent | undefined = action.icon; - if (!Icon && hasIcons) Icon = TransparentIcon; + let CustomIcon: ComponentClass | FunctionComponent | undefined = action.icon; + if (!CustomIcon && hasIcons) CustomIcon = TransparentIcon; let tooltip; if (isDisabled) { @@ -206,11 +242,14 @@ function PageDropdownActionItem(props: { tooltip = t(`Select at least one item from the list`); isButtonDisabled = true; } + return ( : undefined} + id={getID(action)} + data-cy={getID(action)?.split('.').join('-')} + isAriaDisabled={isButtonDisabled} onClick={() => { switch (action.selection) { case PageActionSelection.None: @@ -224,10 +263,22 @@ function PageDropdownActionItem(props: { break; } }} - isAriaDisabled={isButtonDisabled} - id={getID(action)} - data-cy={getID(action)?.split('.').join('-')} + style={{ + color: + action.isDanger && !isDisabled ? getPatternflyColor(PFColorE.Danger) : undefined, + }} > + {CustomIcon ? ( + + + + ) : undefined} {action.label} @@ -236,8 +287,8 @@ function PageDropdownActionItem(props: { } case PageActionType.Link: { - let Icon: ComponentClass | FunctionComponent | undefined = action.icon; - if (!Icon && hasIcons) Icon = TransparentIcon; + let CustomIcon: ComponentClass | FunctionComponent | undefined = action.icon; + if (!CustomIcon && hasIcons) CustomIcon = TransparentIcon; const tooltip = isDisabled ? isDisabled : action.tooltip; let to: string; @@ -258,14 +309,27 @@ function PageDropdownActionItem(props: { return ( : undefined} - component={{action.label}} + data-cy={getID(action)?.split('.').join('-')} style={{ color: action.isDanger && !isDisabled ? getPatternflyColor(PFColorE.Danger) : undefined, }} - /> + > + {CustomIcon ? ( + + + + ) : undefined} + {action.label} + ); } @@ -295,7 +359,7 @@ function PageDropdownActionItem(props: { } case PageActionType.Seperator: - return ; + return ; } } diff --git a/framework/PageInputs/PageMultiSelect.tsx b/framework/PageInputs/PageMultiSelect.tsx index abe9678555..a74e460563 100644 --- a/framework/PageInputs/PageMultiSelect.tsx +++ b/framework/PageInputs/PageMultiSelect.tsx @@ -331,7 +331,7 @@ export function PageMultiSelect< isOpen={open} onOpenChange={setOpen} toggle={Toggle} - popperProps={{ appendTo: () => document.body }} + popperProps={{ appendTo: () => document.body, preventOverflow: true, enableFlip: true }} innerRef={selectListRef} > diff --git a/framework/PageInputs/PageSingleSelect.tsx b/framework/PageInputs/PageSingleSelect.tsx index a052d03c07..74e2d18842 100644 --- a/framework/PageInputs/PageSingleSelect.tsx +++ b/framework/PageInputs/PageSingleSelect.tsx @@ -311,7 +311,7 @@ export function PageSingleSelect< isOpen={open} onOpenChange={setOpen} toggle={props.toggle ?? Toggle} - popperProps={{ appendTo: () => document.body }} + popperProps={{ appendTo: () => document.body, preventOverflow: true, enableFlip: true }} shouldFocusToggleOnSelect innerRef={selectListRef} > diff --git a/framework/PageToolbar/PageToolbar.tsx b/framework/PageToolbar/PageToolbar.tsx index e0119cf857..acda0b9c94 100644 --- a/framework/PageToolbar/PageToolbar.tsx +++ b/framework/PageToolbar/PageToolbar.tsx @@ -182,6 +182,7 @@ export function PageToolbar(props: PageToolbarProps) { { credentialType.summary_fields.user_capabilities.delete = false; }); cy.mount(); - cy.get('button[aria-label="Actions"]').click(); - cy.contains('a.pf-v5-c-dropdown__menu-item', 'Delete credential type').should( + cy.getByDataCy('actions-dropdown').click(); + cy.contains('#delete-credential-type', /^Delete credential type$/).should( 'have.attr', 'aria-disabled', 'true' diff --git a/frontend/awx/access/credential-types/CredentialTypes.cy.tsx b/frontend/awx/access/credential-types/CredentialTypes.cy.tsx index bbaefd59d4..acb1838141 100644 --- a/frontend/awx/access/credential-types/CredentialTypes.cy.tsx +++ b/frontend/awx/access/credential-types/CredentialTypes.cy.tsx @@ -30,12 +30,12 @@ describe('Credential Types List', () => { cy.mount(); cy.contains('tr', 'VMware vCenter').within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete credential type$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#delete-credential-type', /^Delete credential type$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); it('Delete credential type row action is disabled if the user does not have permission to edit credential types', () => { @@ -43,12 +43,12 @@ describe('Credential Types List', () => { cy.contains('tr', 'test').within(() => { // user_capabilities.delete: false cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete credential type$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#delete-credential-type', /^Delete credential type$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); it('Edit credential type row action is disabled for a managed credential type', () => { diff --git a/frontend/awx/access/credentials/CredentialPage/CredentialPage.cy.tsx b/frontend/awx/access/credentials/CredentialPage/CredentialPage.cy.tsx index 9e587559aa..54d936e09b 100644 --- a/frontend/awx/access/credentials/CredentialPage/CredentialPage.cy.tsx +++ b/frontend/awx/access/credentials/CredentialPage/CredentialPage.cy.tsx @@ -22,10 +22,12 @@ describe('CredentialPage', () => { cy.intercept('GET', '/api/v2/credentials/*', credential); }); cy.mount(); - cy.get('.toggle-kebab') - .click() - .get('a.pf-m-aria-disabled ') - .should('have.attr', 'aria-disabled', 'true'); + cy.getByDataCy('actions-dropdown').click(); + cy.contains('#delete-credential', /^Delete credential$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); it('Should disable edit button', () => { @@ -34,7 +36,11 @@ describe('CredentialPage', () => { cy.intercept('GET', '/api/v2/credentials/*', credential); }); cy.mount(); - cy.get('#edit-credential').should('have.attr', 'aria-disabled', 'true'); + cy.contains('#edit-credential', /^Edit credential$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); it('Should render all the tabs', () => { const tabNames: string[] = [ diff --git a/frontend/awx/access/credentials/Credentials.cy.tsx b/frontend/awx/access/credentials/Credentials.cy.tsx index d8e7049437..f3929f03a9 100644 --- a/frontend/awx/access/credentials/Credentials.cy.tsx +++ b/frontend/awx/access/credentials/Credentials.cy.tsx @@ -40,12 +40,12 @@ describe('Credentials.cy.ts', () => { const credential = results[1]; // credential with summary_fields.user_capabilities.delete: false cy.contains('tr', credential.name).within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete credential$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#delete-credential', /^Delete credential$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); }); diff --git a/frontend/awx/access/roles/AwxRolePage.cy.tsx b/frontend/awx/access/roles/AwxRolePage.cy.tsx index ecbb6158c4..6a6bfc331d 100644 --- a/frontend/awx/access/roles/AwxRolePage.cy.tsx +++ b/frontend/awx/access/roles/AwxRolePage.cy.tsx @@ -50,11 +50,9 @@ describe('AwxRoles', () => { .parent() .within(() => { cy.get('#edit-role').should('have.attr', 'aria-disabled', 'true'); - cy.get('.pf-v5-c-dropdown__toggle').click(); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Delete role$/) - .should('have.attr', 'aria-disabled', 'true'); + cy.getByDataCy('actions-dropdown').click(); }); + cy.contains('#delete-role', /^Delete role$/).should('have.attr', 'aria-disabled', 'true'); }); it('should enable edit and delete row action for editable roles when user is superuser', () => { @@ -63,11 +61,9 @@ describe('AwxRoles', () => { .parent() .within(() => { cy.get('#edit-role').should('have.attr', 'aria-disabled', 'false'); - cy.get('.pf-v5-c-dropdown__toggle').click(); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Delete role$/) - .should('have.attr', 'aria-disabled', 'false'); + cy.getByDataCy('actions-dropdown').click(); }); + cy.contains('#delete-role', /^Delete role$/).should('not.have.attr', 'aria-disabled', 'true'); }); it('should disable edit and delete row action for editable roles when user is normal user', () => { @@ -76,11 +72,9 @@ describe('AwxRoles', () => { .parent() .within(() => { cy.get('#edit-role').should('have.attr', 'aria-disabled', 'true'); - cy.get('.pf-v5-c-dropdown__toggle').click(); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Delete role$/) - .should('have.attr', 'aria-disabled', 'true'); + cy.getByDataCy('actions-dropdown').click(); }); + cy.contains('#delete-role', /^Delete role$/).should('have.attr', 'aria-disabled', 'true'); }); it('should enable Create Role button if the user has permission to create roles', () => { diff --git a/frontend/awx/access/teams/TeamPage/TeamPage.cy.tsx b/frontend/awx/access/teams/TeamPage/TeamPage.cy.tsx index 6550158b17..fdf2fc8f7f 100644 --- a/frontend/awx/access/teams/TeamPage/TeamPage.cy.tsx +++ b/frontend/awx/access/teams/TeamPage/TeamPage.cy.tsx @@ -15,12 +15,8 @@ describe('TeamPage', () => { cy.contains('button', 'Edit team').should('have.attr', 'aria-disabled', 'false'); }); it('Delete button is visible but disabled due to lack of permissions to delete', () => { - cy.get('button[aria-label="Actions"]').click(); - cy.contains('a.pf-v5-c-dropdown__menu-item', 'Delete team').should( - 'have.attr', - 'aria-disabled', - 'true' - ); + cy.getByDataCy('actions-dropdown').click(); + cy.contains('#delete-team', /^Delete team$/).should('have.attr', 'aria-disabled', 'true'); }); it('Displays tabs for Details, Access and Roles', () => { cy.get('.pf-v5-c-tabs__item').should('have.length', 4); diff --git a/frontend/awx/administration/applications/Applications.cy.tsx b/frontend/awx/administration/applications/Applications.cy.tsx index d93295c484..560c86a91c 100644 --- a/frontend/awx/administration/applications/Applications.cy.tsx +++ b/frontend/awx/administration/applications/Applications.cy.tsx @@ -72,12 +72,12 @@ describe('Applications List', () => { .then(() => { cy.contains('tr', 'test').within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete application$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#delete-application', /^Delete application$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); }); @@ -136,12 +136,12 @@ describe('Applications List', () => { cy.contains('tr', 'test').within(() => { // user_capabilities.delete: false cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete application$/).should( - 'have.attr', - 'aria-disabled', - 'false' - ); }); + cy.contains('#delete-application', /^Delete application$/).should( + 'not.have.attr', + 'aria-disabled', + 'true' + ); }); it('Edit application row action is enabled if the user has permission to edit application', () => { diff --git a/frontend/awx/administration/execution-environments/ExecutionEnvironments.cy.tsx b/frontend/awx/administration/execution-environments/ExecutionEnvironments.cy.tsx index c3a84655ba..6ba17f90ec 100644 --- a/frontend/awx/administration/execution-environments/ExecutionEnvironments.cy.tsx +++ b/frontend/awx/administration/execution-environments/ExecutionEnvironments.cy.tsx @@ -87,12 +87,12 @@ describe('Execution Environments List', () => { .then(() => { cy.contains('tr', 'test').within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete execution environment$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#delete-execution-environment', /^Delete execution environment$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); }); @@ -178,12 +178,12 @@ describe('Execution Environments List', () => { .then(() => { cy.contains('tr', 'test').within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete execution environment$/).should( - 'have.attr', - 'aria-disabled', - 'false' - ); }); + cy.contains('#delete-execution-environment', /^Delete execution environment$/).should( + 'not.have.attr', + 'aria-disabled', + 'true' + ); }); }); diff --git a/frontend/awx/administration/instance-groups/InstanceGroups.cy.tsx b/frontend/awx/administration/instance-groups/InstanceGroups.cy.tsx index 04c20067b4..e56bdb59f5 100644 --- a/frontend/awx/administration/instance-groups/InstanceGroups.cy.tsx +++ b/frontend/awx/administration/instance-groups/InstanceGroups.cy.tsx @@ -32,18 +32,18 @@ describe('Instance Groups List', () => { }); it('Create group button is disabled if the user does not have permission to create instance groups', () => { cy.mount(); - cy.get('button[data-cy="create-group"]').should('have.attr', 'disabled'); + cy.get('button[data-cy="create-group"]').should('have.attr', 'aria-disabled', 'true'); }); it('Delete instance group row action is disabled if the user does not have permission to edit instance groups', () => { cy.mount(); cy.contains('tr', 'Container Group 01').within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete container group$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#delete-container-group', /^Delete container group$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); it('Edit instance group row action is disabled if the user does not have permission to edit instance groups', () => { cy.mount(); diff --git a/frontend/awx/administration/instances/Instances.cy.tsx b/frontend/awx/administration/instances/Instances.cy.tsx index 6c4cba0aca..08bd3f4e24 100644 --- a/frontend/awx/administration/instances/Instances.cy.tsx +++ b/frontend/awx/administration/instances/Instances.cy.tsx @@ -34,7 +34,7 @@ describe('Instances list', () => { cy.get('[data-cy="actions-dropdown"]').click(); cy.get('[data-cy="add-instance"]').should('be.visible'); cy.get('[data-cy="remove-instance"]').should('be.visible'); - cy.get('[data-cy="remove-instance"]').should('have.attr', 'aria-disabled', 'true'); + cy.get('#remove-instance').should('have.attr', 'aria-disabled', 'true'); cy.get('tbody').find('tr').should('have.length', 10); }); @@ -91,8 +91,8 @@ describe('Instances list', () => { .then(() => { cy.get('[data-cy="checkbox-column-cell"]').first().click(); cy.get('[data-cy="actions-dropdown"]').click(); - cy.get('[data-cy="remove-instance"]').should('be.visible'); - cy.get('[data-cy="remove-instance"]').should('have.attr', 'aria-disabled', 'true'); + cy.get('#remove-instance').should('be.visible'); + cy.get('#remove-instance').should('have.attr', 'aria-disabled', 'true'); }); }); @@ -107,8 +107,8 @@ describe('Instances list', () => { .then(() => { cy.get('[data-cy="checkbox-column-cell"]').first().click(); cy.get('[data-cy="actions-dropdown"]').click(); - cy.get('[data-cy="remove-instance"]').should('be.visible'); - cy.get('[data-cy="remove-instance"]').should('have.attr', 'aria-disabled', 'false'); + cy.get('#remove-instance').should('be.visible'); + cy.get('#remove-instance').should('not.have.attr', 'aria-disabled', 'true'); }); }); @@ -123,8 +123,8 @@ describe('Instances list', () => { .then(() => { cy.get('[data-cy="checkbox-column-cell"]').first().click(); cy.get('[data-cy="actions-dropdown"]').click(); - cy.get('[data-cy="remove-instance"]').should('be.visible'); - cy.get('[data-cy="remove-instance"]').should('have.attr', 'aria-disabled', 'false'); + cy.get('#remove-instance').should('be.visible'); + cy.get('#remove-instance').should('not.have.attr', 'aria-disabled', 'true'); }); }); @@ -139,8 +139,8 @@ describe('Instances list', () => { .then(() => { cy.get('[data-cy="checkbox-column-cell"]').first().click(); cy.get('[data-cy="actions-dropdown"]').click(); - cy.get('[data-cy="remove-instance"]').should('be.visible'); - cy.get('[data-cy="remove-instance"]').should('have.attr', 'aria-disabled', 'true'); + cy.get('#remove-instance').should('be.visible'); + cy.get('#remove-instance').should('have.attr', 'aria-disabled', 'true'); }); }); }); diff --git a/frontend/awx/administration/instances/InstancesPage.cy.tsx b/frontend/awx/administration/instances/InstancesPage.cy.tsx index 768c544d31..f56205731a 100644 --- a/frontend/awx/administration/instances/InstancesPage.cy.tsx +++ b/frontend/awx/administration/instances/InstancesPage.cy.tsx @@ -23,9 +23,9 @@ describe('Instances Page', () => { cy.getByDataCy('instances-peers-tab').should('be.enabled'); cy.getByDataCy('actions-dropdown').click(); cy.getByDataCy('edit-instance').should('be.visible'); - cy.getByDataCy('edit-instance').should('have.attr', 'aria-disabled', 'false'); + cy.get('#edit-instance').should('not.have.attr', 'aria-disabled', 'true'); cy.getByDataCy('remove-instance').should('be.visible'); - cy.getByDataCy('remove-instance').should('have.attr', 'aria-disabled', 'false'); + cy.get('#remove-instance').should('not.have.attr', 'aria-disabled', 'true'); cy.getByDataCy('run-health-check').should('be.visible'); cy.getByDataCy('run-health-check').should('have.attr', 'aria-disabled', 'false'); }); @@ -44,7 +44,7 @@ describe('Instances Page', () => { }).as('isK8s'); cy.mount(); cy.get('[data-cy="actions-dropdown"]').click(); - cy.get('[data-cy="edit-instance"]').should('have.attr', 'aria-disabled', 'false'); + cy.get('#edit-instance').should('not.have.attr', 'aria-disabled', 'true'); }); it('only admin users can edit instance', () => { @@ -57,7 +57,7 @@ describe('Instances Page', () => { .then(() => { cy.get('[data-cy="actions-dropdown"]').click(); cy.getByDataCy('edit-instance').should('be.visible'); - cy.getByDataCy('edit-instance').should('have.attr', 'aria-disabled', 'false'); + cy.get('#edit-instance').should('not.have.attr', 'aria-disabled', 'true'); }); }); @@ -103,7 +103,7 @@ describe('Instances Page', () => { cy.wait('@isK8s').then(() => { cy.getByDataCy('actions-dropdown').click(); cy.getByDataCy('remove-instance').should('be.visible'); - cy.getByDataCy('remove-instance').should('have.attr', 'aria-disabled', 'false'); + cy.get('#remove-instance').should('not.have.attr', 'aria-disabled', 'true'); }); }); @@ -117,7 +117,7 @@ describe('Instances Page', () => { .then(() => { cy.getByDataCy('actions-dropdown').click(); cy.getByDataCy('remove-instance').should('be.visible'); - cy.getByDataCy('remove-instance').should('have.attr', 'aria-disabled', 'false'); + cy.get('#remove-instance').should('not.have.attr', 'aria-disabled', 'true'); }); }); diff --git a/frontend/awx/administration/workflow-approvals/WorkflowApprovals.cy.tsx b/frontend/awx/administration/workflow-approvals/WorkflowApprovals.cy.tsx index 20a419f687..b0c5a32aee 100644 --- a/frontend/awx/administration/workflow-approvals/WorkflowApprovals.cy.tsx +++ b/frontend/awx/administration/workflow-approvals/WorkflowApprovals.cy.tsx @@ -111,12 +111,12 @@ describe('Workflow Approvals List', () => { cy.contains('tr', 'read only approval').within(() => { // user_capabilities.delete: false cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete workflow approval$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#delete-workflow-approval', /^Delete workflow approval$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); it('Delete workflow approval row action is enabled if the user has permission to delete workflow approvals', () => { @@ -124,12 +124,12 @@ describe('Workflow Approvals List', () => { cy.contains('tr', 'can delete approval').within(() => { // user_capabilities.delete: true cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete workflow approval$/).should( - 'have.attr', - 'aria-disabled', - 'false' - ); }); + cy.contains('#delete-workflow-approval', /^Delete workflow approval$/).should( + 'not.have.attr', + 'aria-disabled', + 'true' + ); }); it('Approve row action is enabled if the user has permission to approve', () => { @@ -222,7 +222,10 @@ describe('Workflow Approvals List', () => { statusCode: 204, }).as('deleteRequest'); cy.filterTableByMultiSelect('name', ['can delete approval']); - cy.clickTableRowKebabAction('can delete approval', 'delete-workflow-approval', false); + cy.clickTableRowAction('name', 'can delete approval', 'delete-workflow-approval', { + disableFilter: true, + inKebab: true, + }); cy.get('#confirm').click(); cy.clickButton(/^Delete workflow approvals/); cy.wait('@deleteRequest'); diff --git a/frontend/awx/resources/groups/GroupRelatedGroups.cy.tsx b/frontend/awx/resources/groups/GroupRelatedGroups.cy.tsx index 9df57e31c3..38000ba263 100644 --- a/frontend/awx/resources/groups/GroupRelatedGroups.cy.tsx +++ b/frontend/awx/resources/groups/GroupRelatedGroups.cy.tsx @@ -151,7 +151,7 @@ inventories.forEach((inventory) => { .should('be.an', 'array') .then(() => { cy.get('[data-cy="add-group"]').click(); - cy.get('[data-cy="create-new-group"]').should('have.attr', 'aria-disabled', 'true'); + cy.get('#create-new-group').should('have.attr', 'aria-disabled', 'true'); }); }); } @@ -165,7 +165,7 @@ inventories.forEach((inventory) => { cy.get(`[data-cy="run-command"]`); cy.get(`[data-cy="add-group"]`).should('not.exist'); - cy.get(`[aria-label="Actions"]`).should('not.exist'); + cy.get(`[data-cy="actions-dropdown"]`).should('not.exist'); }); } @@ -178,7 +178,7 @@ inventories.forEach((inventory) => { cy.get(`[data-cy="run-command"]`); cy.get(`[data-cy="add-group"]`); - cy.get(`[aria-label="Actions"]`).click(); + cy.get(`[data-cy="actions-dropdown"]`).click(); cy.get(`[data-cy="disassociate-selected-groups"]`); }); } diff --git a/frontend/awx/resources/hosts/Hosts.cy.tsx b/frontend/awx/resources/hosts/Hosts.cy.tsx index 3986a2bb35..9cda2a1dc5 100644 --- a/frontend/awx/resources/hosts/Hosts.cy.tsx +++ b/frontend/awx/resources/hosts/Hosts.cy.tsx @@ -381,7 +381,7 @@ function disableDeleteRowAction(component: React.ReactElement, params: paramsTyp .then(() => { cy.mount(component, params); cy.get(`tr [data-cy="actions-dropdown"]`).click(); - cy.get(`[data-cy="delete-host"]`).as('deleteButton'); + cy.get('#delete-host').as('deleteButton'); cy.get('@deleteButton').should('have.attr', 'aria-disabled', 'true'); cy.get('@deleteButton').click(); cy.hasTooltip('This cannot be deleted due to insufficient permission'); diff --git a/frontend/awx/resources/inventories/Inventories.cy.tsx b/frontend/awx/resources/inventories/Inventories.cy.tsx index 30b538ad41..e4f87049a5 100644 --- a/frontend/awx/resources/inventories/Inventories.cy.tsx +++ b/frontend/awx/resources/inventories/Inventories.cy.tsx @@ -59,7 +59,7 @@ describe('Inventories', () => { })); cy.mount(); cy.contains('button', /^Create inventory$/).as('createButton'); - cy.get('@createButton').should('have.attr', 'disabled'); + cy.get('@createButton').should('have.attr', 'aria-disabled', 'true'); cy.get('@createButton').click({ force: true }); cy.hasTooltip( /^You do not have permission to create an inventory. Please contact your organization administrator if there is an issue with your access.$/ @@ -76,10 +76,8 @@ describe('Inventories', () => { cy.contains('tr', (inventory as Inventory).name).within(() => { cy.get('button.toggle-kebab').click(); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Delete inventory$/) - .as('deleteButton'); }); + cy.contains('#delete-inventory', /^Delete inventory$/).as('deleteButton'); cy.get('@deleteButton').should('have.attr', 'aria-disabled', 'true'); cy.get('@deleteButton').click(); cy.hasTooltip('The inventory cannot be deleted due to insufficient permission'); @@ -114,10 +112,8 @@ describe('Inventories', () => { cy.contains('tr', (inventory as Inventory).name).within(() => { cy.get('button.toggle-kebab').click(); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Copy inventory$/) - .as('copyButton'); }); + cy.contains('button', /^Copy inventory$/).as('copyButton'); cy.get('@copyButton').should('have.attr', 'aria-disabled', 'true'); cy.get('@copyButton').click(); cy.get('@copyButton').hasTooltip( @@ -135,10 +131,8 @@ describe('Inventories', () => { const inventory = results.find((i) => i.id === 1); cy.contains('tr', (inventory as Inventory).name).within(() => { cy.get('button.toggle-kebab').click(); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Copy inventory$/) - .as('copyButton'); }); + cy.contains('button', /^Copy inventory$/).as('copyButton'); cy.get('@copyButton').should('have.attr', 'aria-disabled', 'true'); cy.get('@copyButton').click(); cy.get('@copyButton').hasTooltip('Inventories with sources cannot be copied'); @@ -181,15 +175,11 @@ describe('Inventories', () => { cy.contains(/^Please create an inventory by using the button below.$/); cy.contains('button', /^Create inventory$/).should('be.visible'); cy.contains('button', /^Create inventory$/).click(); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Create inventory$/) - .should('exist'); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Create smart inventory$/) - .should('exist'); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Create constructed inventory$/) - .should('exist'); + cy.contains('#create-inventory', /^Create inventory$/).should('exist'); + cy.contains('#create-smart-inventory', /^Create smart inventory$/).should('exist'); + cy.contains('#create-constructed-inventory', /^Create constructed inventory$/).should( + 'exist' + ); }); it('display Empty state for user without permission to create teams', () => { diff --git a/frontend/awx/resources/inventories/InventoryPage/InventorySources.cy.tsx b/frontend/awx/resources/inventories/InventoryPage/InventorySources.cy.tsx index af41967aa6..db3fcbd127 100644 --- a/frontend/awx/resources/inventories/InventoryPage/InventorySources.cy.tsx +++ b/frontend/awx/resources/inventories/InventoryPage/InventorySources.cy.tsx @@ -37,12 +37,12 @@ describe('InventorySources.cy.ts', () => { const source = results[2]; // source with status "running" cy.contains('tr', source.name).within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete inventory source$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#delete-inventory-source', /^Delete inventory source$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); }); @@ -55,12 +55,12 @@ describe('InventorySources.cy.ts', () => { const source = results[1]; // sources with summary_fields.user_capabilities.delete: false cy.contains('tr', source.name).within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete inventory source$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#delete-inventory-source', /^Delete inventory source$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); }); }); diff --git a/frontend/awx/resources/projects/Projects.cy.tsx b/frontend/awx/resources/projects/Projects.cy.tsx index 28b9456f4e..de1f9884f0 100644 --- a/frontend/awx/resources/projects/Projects.cy.tsx +++ b/frontend/awx/resources/projects/Projects.cy.tsx @@ -158,13 +158,7 @@ describe('projects.cy.ts', () => { cy.mount(); cy.filterTableByMultiSelect('name', [' Project 1 Org 0']); cy.selectTableRowByCheckbox('name', ' Project 1 Org 0', { disableFilter: true }); - cy.get('.page-table-toolbar').within(() => { - cy.get('.toggle-kebab') - .click() - .get('.pf-v5-c-dropdown__menu-item') - .contains('a', 'Cancel projects') - .click(); - }); + cy.clickToolbarKebabAction('cancel-projects'); cy.get('.pf-v5-c-modal-box').within(() => { cy.hasAlert( '1 of the selected project sync jobs cannot be canceled because they are not running.' @@ -185,13 +179,7 @@ describe('projects.cy.ts', () => { cy.selectTableRowByCheckbox('name', ' Project 2 Org 0', { disableFilter: true, }); - cy.get('.page-table-toolbar').within(() => { - cy.get('.toggle-kebab') - .click() - .get('.pf-v5-c-dropdown__menu-item') - .contains('a', 'Cancel projects') - .click(); - }); + cy.clickToolbarKebabAction('cancel-projects'); cy.get('.pf-v5-c-modal-box').within(() => { cy.hasAlert( '1 of the selected project sync jobs cannot be cancelled due to insufficient permissions.' @@ -212,14 +200,14 @@ describe('projects.cy.ts', () => { .parent() .within(() => { cy.get('#sync-project').should('have.attr', 'aria-disabled', 'true'); - cy.get('.pf-v5-c-dropdown__toggle').click(); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Copy project$/) - .should('have.attr', 'aria-disabled', 'true'); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Delete project$/) - .should('have.attr', 'aria-disabled', 'true'); + cy.getByDataCy('actions-dropdown').click(); }); + cy.contains('#copy-project', /^Copy project$/).should('have.attr', 'aria-disabled', 'true'); + cy.contains('#delete-project', /^Delete project$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); it('Sync project kebab button is visible for project with non-active sync status and is hidden for project with active sync status', () => { diff --git a/frontend/awx/resources/templates/TemplatePage/TemplateSurvey.cy.tsx b/frontend/awx/resources/templates/TemplatePage/TemplateSurvey.cy.tsx index 79e15e78c5..8b2a215cfb 100644 --- a/frontend/awx/resources/templates/TemplatePage/TemplateSurvey.cy.tsx +++ b/frontend/awx/resources/templates/TemplatePage/TemplateSurvey.cy.tsx @@ -75,11 +75,13 @@ describe('TemplateSurvey', () => { cy.get('[data-cy="actions-column-cell"]').within(() => { cy.get('[data-cy="edit-question"]').should('have.attr', 'aria-disabled', 'true'); }); - cy.get('.pf-v5-c-dropdown__toggle').click(); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains('Delete question') - .should('have.attr', 'aria-disabled', 'true'); + cy.getByDataCy('actions-dropdown').click(); }); + cy.contains('#delete-question', /^Delete question$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); }); diff --git a/frontend/awx/resources/templates/TemplatesList.cy.tsx b/frontend/awx/resources/templates/TemplatesList.cy.tsx index cef662f3f4..5cd36282c3 100644 --- a/frontend/awx/resources/templates/TemplatesList.cy.tsx +++ b/frontend/awx/resources/templates/TemplatesList.cy.tsx @@ -151,7 +151,7 @@ describe('TemplatesList', () => { it('Create Template button is disabled if the user does not have permission to create templates', () => { cy.mount(); - cy.contains('.pf-v5-c-dropdown__toggle', 'Create template').should('be.disabled'); + cy.contains('button', /^Create template$/).should('have.attr', 'aria-disabled', 'true'); }); it('Should render template create form for users with proper permissions', () => { @@ -172,7 +172,7 @@ describe('TemplatesList', () => { }, })); cy.mount(); - cy.contains('.pf-v5-c-dropdown__toggle', 'Create template').should('not.be.disabled'); + cy.contains('button', /^Create template$/).should('not.be.disabled'); }); it('Delete Template button renders delete modal', () => { diff --git a/frontend/awx/views/jobs/JobHeader.cy.tsx b/frontend/awx/views/jobs/JobHeader.cy.tsx index 64fcbe59f3..949f84c1d5 100644 --- a/frontend/awx/views/jobs/JobHeader.cy.tsx +++ b/frontend/awx/views/jobs/JobHeader.cy.tsx @@ -20,11 +20,7 @@ describe('Job Page', () => { it('Delete button is disabled on a running job', () => { cy.mount(, { path: ':job_type/:id', initialEntries: ['/workflow/1'] }); cy.getByDataCy('actions-dropdown').click(); - cy.contains('[data-cy="delete-job"]', 'Delete job').should( - 'have.attr', - 'aria-disabled', - 'true' - ); + cy.contains('#delete-job', /^Delete job$/).should('have.attr', 'aria-disabled', 'true'); }); it('Delete button is enabled on a finished job', () => { cy.intercept( @@ -38,11 +34,7 @@ describe('Job Page', () => { ); cy.mount(, { path: ':job_type/:id', initialEntries: ['/workflow/1'] }); cy.getByDataCy('actions-dropdown').click(); - cy.contains('[data-cy="delete-job"]', 'Delete job').should( - 'have.attr', - 'aria-disabled', - 'false' - ); + cy.contains('#delete-job', /^Delete job$/).should('not.have.attr', 'aria-disabled', 'true'); }); it('Cancel button is disabled on a finished job', () => { cy.intercept( diff --git a/frontend/awx/views/jobs/Jobs.cy.tsx b/frontend/awx/views/jobs/Jobs.cy.tsx index 992fef0ffa..64a901cf3f 100644 --- a/frontend/awx/views/jobs/Jobs.cy.tsx +++ b/frontend/awx/views/jobs/Jobs.cy.tsx @@ -52,7 +52,10 @@ describe('Jobs.cy.ts', () => { }).as('reqJobs'); const job = jobs[0]; cy.selectTableRow(job.name, false); - cy.clickTableRowKebabAction(job.name, 'delete-job', false); + cy.clickTableRowAction('name', job.name, 'delete-job', { + disableFilter: true, + inKebab: true, + }); cy.contains('Permanently delete jobs').should('be.visible'); cy.get('input[id="confirm"]').should('be.visible'); cy.get('#confirm').click(); @@ -71,15 +74,11 @@ describe('Jobs.cy.ts', () => { const job = results[5]; // job with status "running" cy.contains('tr', job.id).within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete job$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#delete-job', /^Delete job$/).should('have.attr', 'aria-disabled', 'true'); }); }); - it('row action to delete job is disabled if the user does not have permissions', () => { + it('row action to delete job is disabled if the user does not have permissions', () => { cy.mount(); cy.fixture('jobs.json') .its('results') @@ -88,12 +87,8 @@ describe('Jobs.cy.ts', () => { const job = results[4]; // job with summary_fields.user_capabilities.delete: false cy.contains('tr', job.id).within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete job$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#delete-job', /^Delete job$/).should('have.attr', 'aria-disabled', 'true'); }); }); it('bulk deletion confirmation contains message about selected jobs that cannot be deleted', () => { @@ -119,12 +114,8 @@ describe('Jobs.cy.ts', () => { const job = results[4]; // job with status "successful" cy.contains('tr', job.id).within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Cancel job$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#cancel-job', /^Cancel job$/).should('have.attr', 'aria-disabled', 'true'); }); }); it('row action to cancel job is disabled if the user does not have permissions', () => { @@ -136,12 +127,8 @@ describe('Jobs.cy.ts', () => { const job = results[5]; // job with summary_fields.user_capabilities.start: false cy.contains('tr', job.id).within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Cancel job$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#cancel-job', /^Cancel job$/).should('have.attr', 'aria-disabled', 'true'); }); }); diff --git a/frontend/awx/views/schedules/Schedules.cy.tsx b/frontend/awx/views/schedules/Schedules.cy.tsx index 87f44d1b63..542301c18b 100644 --- a/frontend/awx/views/schedules/Schedules.cy.tsx +++ b/frontend/awx/views/schedules/Schedules.cy.tsx @@ -126,11 +126,13 @@ describe('schedules .cy.ts', () => { .parent() .within(() => { cy.get('input.pf-v5-c-switch__input').should('have.attr', 'disabled'); - cy.get('.pf-v5-c-dropdown__toggle').click(); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Delete schedule$/) - .should('have.attr', 'aria-disabled', 'true'); + cy.getByDataCy('actions-dropdown').click(); }); + cy.contains('#delete-schedule', /^Delete schedule$/).should( + 'have.attr', + 'aria-disabled', + 'true' + ); }); }); diff --git a/frontend/eda/access/roles/EdaRolePage.cy.tsx b/frontend/eda/access/roles/EdaRolePage.cy.tsx index 7f6889b850..cb053046c1 100644 --- a/frontend/eda/access/roles/EdaRolePage.cy.tsx +++ b/frontend/eda/access/roles/EdaRolePage.cy.tsx @@ -16,12 +16,8 @@ describe('EdaRolePage', () => { cy.contains('button', 'Edit role').should('have.attr', 'aria-disabled', 'true'); }); it('Delete button is visible and disabled', () => { - cy.get('button[aria-label="Actions"]').click(); - cy.contains('a.pf-v5-c-dropdown__menu-item', 'Delete role').should( - 'have.attr', - 'aria-disabled', - 'true' - ); + cy.getByDataCy('actions-dropdown').click(); + cy.contains('#delete-role', /^Delete role$/).should('have.attr', 'aria-disabled', 'true'); }); it('Displays tab for Details', () => { cy.get('.pf-v5-c-tabs__item').should('have.length', 2); @@ -46,12 +42,8 @@ describe('EdaRolePage', () => { }); it('Delete button is visible and enabled for superuser', () => { cy.mountEda(); - cy.get('button[aria-label="Actions"]').click(); - cy.contains('a.pf-v5-c-dropdown__menu-item', 'Delete role').should( - 'have.attr', - 'aria-disabled', - 'false' - ); + cy.getByDataCy('actions-dropdown').click(); + cy.contains('#delete-role', /^Delete role$/).should('not.have.attr', 'aria-disabled', 'true'); }); it('Edit button is visible and disabled when user is not superuser', () => { cy.mountEda(, undefined, 'edaNormalUser.json'); @@ -59,12 +51,8 @@ describe('EdaRolePage', () => { }); it('Delete button is visible and disabled when user is not superuser', () => { cy.mountEda(, undefined, 'edaNormalUser.json'); - cy.get('button[aria-label="Actions"]').click(); - cy.contains('a.pf-v5-c-dropdown__menu-item', 'Delete role').should( - 'have.attr', - 'aria-disabled', - 'true' - ); + cy.getByDataCy('actions-dropdown').click(); + cy.contains('#delete-role', /^Delete role$/).should('have.attr', 'aria-disabled', 'true'); }); it('Displays tab for Details', () => { cy.mountEda(); diff --git a/frontend/eda/access/roles/EdaRoles.cy.tsx b/frontend/eda/access/roles/EdaRoles.cy.tsx index 2ea235cca9..11a64230d7 100644 --- a/frontend/eda/access/roles/EdaRoles.cy.tsx +++ b/frontend/eda/access/roles/EdaRoles.cy.tsx @@ -1,5 +1,7 @@ // import { ToolbarFilterType } from '../../../../framework'; // import * as useOptions from '../../../common/crud/useOptions'; +import { EdaItemsResponse } from '../../common/EdaItemsResponse'; +import { EdaRole } from '../../interfaces/EdaRole'; import { EdaRoles } from './EdaRoles'; /* @@ -55,42 +57,81 @@ describe('EdaRoles.cy.ts', () => { }); it('Disables edit and delete row action for built-in roles', () => { + cy.fixture('edaRoleDefinitions').then((edaRoles: EdaItemsResponse) => { + const role = edaRoles.results.find((role) => role.name === 'Activation Admin'); + cy.intercept( + { method: 'GET', url: '/api/eda/v1/role_definitions/*' }, + { + body: { + count: 1, + next: null, + previous: null, + page: 1, + results: [role], + }, + } + ); + }); cy.mountEda(); cy.contains('td', 'Activation Admin') .parent() .within(() => { cy.get('#edit-role').should('have.attr', 'aria-disabled', 'true'); - cy.get('.pf-v5-c-dropdown__toggle').click(); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Delete role$/) - .should('have.attr', 'aria-disabled', 'true'); + cy.getByDataCy('actions-dropdown').click(); }); + cy.contains('#delete-role', /^Delete role$/).should('have.attr', 'aria-disabled', 'true'); }); it('Enables edit and delete row action for editable roles when user is superuser', () => { + cy.fixture('edaRoleDefinitions').then((edaRoles: EdaItemsResponse) => { + const role = edaRoles.results.find((role) => role.name === 'View projects'); + cy.intercept( + { method: 'GET', url: '/api/eda/v1/role_definitions/*' }, + { + body: { + count: 1, + next: null, + previous: null, + page: 1, + results: [role], + }, + } + ); + }); cy.mountEda(); cy.contains('td', 'View projects') .parent() .within(() => { - cy.get('#edit-role').should('have.attr', 'aria-disabled', 'false'); - cy.get('.pf-v5-c-dropdown__toggle').click(); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Delete role$/) - .should('have.attr', 'aria-disabled', 'false'); + cy.get('#edit-role').should('not.have.attr', 'aria-disabled', 'true'); + cy.getByDataCy('actions-dropdown').click(); }); + cy.contains('#delete-role', /^Delete role$/).should('not.have.attr', 'aria-disabled', 'true'); }); it('Disables edit and delete row action for editable roles when user is normal user', () => { + cy.fixture('edaRoleDefinitions').then((edaRoles: EdaItemsResponse) => { + const role = edaRoles.results.find((role) => role.name === 'View projects'); + cy.intercept( + { method: 'GET', url: '/api/eda/v1/role_definitions/*' }, + { + body: { + count: 1, + next: null, + previous: null, + page: 1, + results: [role], + }, + } + ); + }); cy.mountEda(, undefined, 'edaNormalUser.json'); cy.contains('td', 'View projects') .parent() .within(() => { cy.get('#edit-role').should('have.attr', 'aria-disabled', 'true'); - cy.get('.pf-v5-c-dropdown__toggle').click(); - cy.get('.pf-v5-c-dropdown__menu-item') - .contains(/^Delete role$/) - .should('have.attr', 'aria-disabled', 'true'); + cy.getByDataCy('actions-dropdown').click(); }); + cy.contains('#delete-role', /^Delete role$/).should('have.attr', 'aria-disabled', 'true'); }); it('Create Role button is enabled if the user has permission to create roles', () => { diff --git a/frontend/hub/access/roles/Roles.cy.tsx b/frontend/hub/access/roles/Roles.cy.tsx index b3b7fde2f3..dff77f9fd2 100644 --- a/frontend/hub/access/roles/Roles.cy.tsx +++ b/frontend/hub/access/roles/Roles.cy.tsx @@ -73,12 +73,8 @@ describe('Roles List', () => { cy.mount(); cy.contains('tr', 'galaxy.ansible_repository_owner').within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete role$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#delete-role', /^Delete role$/).should('have.attr', 'aria-disabled', 'true'); cy.contains('tr', 'galaxy.ansible_repository_owner').within(() => { cy.get('[data-cy="actions-column-cell"]').within(() => { cy.get(`[data-cy="edit-role"]`).should('have.attr', 'aria-disabled', 'true'); @@ -100,12 +96,8 @@ describe('Roles List', () => { }); cy.contains('tr', 'galaxy.ansible_repository_owner').within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete role$/).should( - 'have.attr', - 'aria-disabled', - 'true' - ); }); + cy.contains('#delete-role', /^Delete role$/).should('have.attr', 'aria-disabled', 'true'); }); it('Row actions for an editable role are enabled if the user is a super user', () => { cy.stub(useHubContext, 'useHubContext').callsFake(() => ({ @@ -119,12 +111,8 @@ describe('Roles List', () => { }); cy.contains('tr', 'galaxy.demorole').within(() => { cy.get('button.toggle-kebab').click(); - cy.contains('.pf-v5-c-dropdown__menu-item', /^Delete role$/).should( - 'have.attr', - 'aria-disabled', - 'false' - ); }); + cy.contains('#delete-role', /^Delete role$/).should('not.have.attr', 'aria-disabled', 'true'); }); it('Create Role button is enabled if the user has permission to create roles', () => { cy.stub(useHubContext, 'useHubContext').callsFake(() => ({