diff --git a/packages/manager/.changeset/pr-12625-tests-1754067693627.md b/packages/manager/.changeset/pr-12625-tests-1754067693627.md new file mode 100644 index 00000000000..ec6c0dd9394 --- /dev/null +++ b/packages/manager/.changeset/pr-12625-tests-1754067693627.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Tests +--- + +M3-10293 Allow action menu items to be selected in 'within' blocks in Cypress ([#12625](https://github.com/linode/manager/pull/12625)) diff --git a/packages/manager/cypress/e2e/core/cloudpulse/alert-errors.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/alert-errors.spec.ts index 6b986d80cb5..36345028a96 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/alert-errors.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/alert-errors.spec.ts @@ -78,9 +78,9 @@ describe('Alerts Listing Page - Error Handling', () => { .findByTitle(`Action menu for Alert ${alertName}`) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle(action).should('be.visible').click(); }); - ui.actionMenuItem.findByTitle(action).should('be.visible').click(); ui.button.findByTitle(action).should('be.visible').click(); cy.wait(alias).then(({ response }) => { ui.toast.assertMessage(response?.body.errors[0].reason); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/alert-show-details.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/alert-show-details.spec.ts index c48eba0e7c8..edae79f9816 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/alert-show-details.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/alert-show-details.spec.ts @@ -132,11 +132,13 @@ describe('Integration Tests for Alert Show Detail Page', () => { .findByTitle(`Action menu for Alert ${label}`) .should('be.visible') .click(); + // Select the "Show Details" option from the action menu + ui.actionMenuItem + .findByTitle('Show Details') + .should('be.visible') + .click(); }); - // Select the "Show Details" option from the action menu - ui.actionMenuItem.findByTitle('Show Details').should('be.visible').click(); - // Verify the URL ends with the expected details page path cy.url().should('endWith', `/detail/${service_type}/${id}`); }); diff --git a/packages/manager/cypress/e2e/core/cloudpulse/alerts-listing-page.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/alerts-listing-page.spec.ts index eebafe4b5ea..485dd160cb7 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/alerts-listing-page.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/alerts-listing-page.spec.ts @@ -382,8 +382,8 @@ describe('Integration Tests for CloudPulse Alerts Listing Page', () => { .findByTitle(`Action menu for Alert ${alertName}`) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle(action).should('be.visible').click(); }); - ui.actionMenuItem.findByTitle(action).should('be.visible').click(); // verify dialog title ui.dialog diff --git a/packages/manager/cypress/e2e/core/cloudpulse/edit-system-alert.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/edit-system-alert.spec.ts index fc99e460e83..44df530332a 100644 --- a/packages/manager/cypress/e2e/core/cloudpulse/edit-system-alert.spec.ts +++ b/packages/manager/cypress/e2e/core/cloudpulse/edit-system-alert.spec.ts @@ -100,11 +100,10 @@ describe('Integration Tests for Edit Alert', () => { .findByTitle(`Action menu for Alert ${label}`) .should('be.visible') .click(); + // Select the "Edit" option from the action menu + ui.actionMenuItem.findByTitle('Edit').should('be.visible').click(); }); - // Select the "Edit" option from the action menu - ui.actionMenuItem.findByTitle('Edit').should('be.visible').click(); - // Verify the URL ends with the expected details page path cy.url().should('endWith', `/edit/${service_type}/${id}`); }); diff --git a/packages/manager/cypress/e2e/core/domains/smoke-clone-domain.spec.ts b/packages/manager/cypress/e2e/core/domains/smoke-clone-domain.spec.ts index e88631fda0f..c0bb9d15138 100644 --- a/packages/manager/cypress/e2e/core/domains/smoke-clone-domain.spec.ts +++ b/packages/manager/cypress/e2e/core/domains/smoke-clone-domain.spec.ts @@ -64,8 +64,8 @@ describe('Clone a Domain', () => { .findByTitle(`Action menu for Domain ${domain.domain}`) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Clone').should('be.visible').click(); }); - ui.actionMenuItem.findByTitle('Clone').should('be.visible').click(); // Cancel cloning when prompted to confirm. ui.drawer @@ -88,8 +88,8 @@ describe('Clone a Domain', () => { .findByTitle(`Action menu for Domain ${domain.domain}`) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Clone').should('be.visible').click(); }); - ui.actionMenuItem.findByTitle('Clone').should('be.visible').click(); // Confirm cloning. ui.drawer diff --git a/packages/manager/cypress/e2e/core/domains/smoke-delete-domain.spec.ts b/packages/manager/cypress/e2e/core/domains/smoke-delete-domain.spec.ts index e6962632185..b3435e5e679 100644 --- a/packages/manager/cypress/e2e/core/domains/smoke-delete-domain.spec.ts +++ b/packages/manager/cypress/e2e/core/domains/smoke-delete-domain.spec.ts @@ -36,8 +36,11 @@ describe('Delete a Domain', () => { .findByTitle(`Action menu for Domain ${domain.domain}`) .should('be.visible') .click(); + ui.actionMenuItem + .findByTitle('Delete') + .should('be.visible') + .click(); }); - ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); // Cancel deletion when prompted to confirm. ui.dialog @@ -60,8 +63,11 @@ describe('Delete a Domain', () => { .findByTitle(`Action menu for Domain ${domain.domain}`) .should('be.visible') .click(); + ui.actionMenuItem + .findByTitle('Delete') + .should('be.visible') + .click(); }); - ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); // Confirm deletion. ui.dialog diff --git a/packages/manager/cypress/e2e/core/images/machine-image-upload.spec.ts b/packages/manager/cypress/e2e/core/images/machine-image-upload.spec.ts index 715d7885f45..f1dac1ca995 100644 --- a/packages/manager/cypress/e2e/core/images/machine-image-upload.spec.ts +++ b/packages/manager/cypress/e2e/core/images/machine-image-upload.spec.ts @@ -193,9 +193,10 @@ describe('machine image', () => { .findByTitle(`Action menu for Image ${initialLabel}`) .should('be.visible') .click(); + + ui.actionMenuItem.findByTitle('Edit').should('be.visible').click(); }); - ui.actionMenuItem.findByTitle('Edit').should('be.visible').click(); cy.wait('@getImage'); mockUpdateImage(mockImage.id, mockImageUpdated).as('updateImage'); @@ -219,6 +220,10 @@ describe('machine image', () => { }); cy.wait(['@getImages', '@updateImage']); + + mockDeleteImage(mockImage.id).as('deleteImage'); + mockGetCustomImages([]).as('getImages'); + cy.get(`[data-qa-image-cell="${mockImage.id}"]`).within(() => { cy.findByText(updatedLabel).should('be.visible'); cy.findByText(initialLabel).should('not.exist'); @@ -226,12 +231,9 @@ describe('machine image', () => { .findByTitle(`Action menu for Image ${updatedLabel}`) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); }); - mockDeleteImage(mockImage.id).as('deleteImage'); - mockGetCustomImages([]).as('getImages'); - ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); - ui.dialog .findByTitle(`Delete Image ${updatedLabel}`) .should('be.visible') diff --git a/packages/manager/cypress/e2e/core/linodes/linode-storage.spec.ts b/packages/manager/cypress/e2e/core/linodes/linode-storage.spec.ts index 6596e116cce..d220e54c39b 100644 --- a/packages/manager/cypress/e2e/core/linodes/linode-storage.spec.ts +++ b/packages/manager/cypress/e2e/core/linodes/linode-storage.spec.ts @@ -150,10 +150,9 @@ describe('linode storage tab', () => { .findByTitle(`Action menu for Disk ${diskName}`) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Resize').should('be.disabled'); }); - ui.actionMenuItem.findByTitle('Resize').should('be.disabled'); - deleteInUseDisk(diskName); ui.button.findByTitle('Add a Disk').should('be.disabled'); @@ -301,10 +300,9 @@ describe('linode storage tab', () => { .findByTitle(`Action menu for Disk ${diskName}`) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Resize').should('be.visible').click(); }); - ui.actionMenuItem.findByTitle('Resize').should('be.visible').click(); - ui.drawer .findByTitle(`Resize ${diskName}`) .should('be.visible') diff --git a/packages/manager/cypress/e2e/core/longview/longview.spec.ts b/packages/manager/cypress/e2e/core/longview/longview.spec.ts index e79309ee796..7e80ccd008a 100644 --- a/packages/manager/cypress/e2e/core/longview/longview.spec.ts +++ b/packages/manager/cypress/e2e/core/longview/longview.spec.ts @@ -375,8 +375,8 @@ describe('longview', () => { .findByTitle(`Action menu for Longview Client ${client.label}`) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); }); - ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); // Confirms that Cloud Manager UI has delete warning message and can cancel deletion. ui.dialog @@ -392,8 +392,8 @@ describe('longview', () => { ui.actionMenu .findByTitle(`Action menu for Longview Client ${client.label}`) .click(); + ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); }); - ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); ui.dialog.findByTitle(`Delete ${client.label}?`).within(() => { ui.buttonGroup diff --git a/packages/manager/cypress/e2e/core/managed/managed-monitors.spec.ts b/packages/manager/cypress/e2e/core/managed/managed-monitors.spec.ts index 1c6ce11d81b..975e2970d6e 100644 --- a/packages/manager/cypress/e2e/core/managed/managed-monitors.spec.ts +++ b/packages/manager/cypress/e2e/core/managed/managed-monitors.spec.ts @@ -111,6 +111,7 @@ describe('Managed Monitors tab', () => { }); // Confirm that monitor label has been updated, then disable the monitor. + mockDisableServiceMonitor(monitorId, newMonitor).as('disableMonitor'); cy.findByText(newLabel) .should('be.visible') .closest('tr') @@ -119,14 +120,13 @@ describe('Managed Monitors tab', () => { .findByTitle(monitorMenuLabel) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Disable').click(); }); - mockDisableServiceMonitor(monitorId, newMonitor).as('disableMonitor'); - ui.actionMenuItem.findByTitle('Disable').click(); - cy.wait('@disableMonitor'); // Confirm that monitor has been disabled, then re-enable the monitor. + mockEnableServiceMonitor(monitorId, newMonitor).as('enableMonitor'); ui.toast.assertMessage('Monitor disabled successfully.'); cy.findByText(newLabel) .should('be.visible') @@ -137,11 +137,9 @@ describe('Managed Monitors tab', () => { .findByTitle(monitorMenuLabel) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Enable').click(); }); - mockEnableServiceMonitor(monitorId, newMonitor).as('enableMonitor'); - ui.actionMenuItem.findByTitle('Enable').click(); - cy.wait('@enableMonitor'); // Confirm that monitor has been re-enabled. @@ -242,10 +240,9 @@ describe('Managed Monitors tab', () => { .findByTitle(monitorMenuLabel) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Delete').click(); }); - ui.actionMenuItem.findByTitle('Delete').click(); - cy.wait('@getMonitor'); // Fill out and submit type-to-confirm. diff --git a/packages/manager/cypress/e2e/core/objectStorageMulticluster/access-keys-multicluster.spec.ts b/packages/manager/cypress/e2e/core/objectStorageMulticluster/access-keys-multicluster.spec.ts index 6aae8857c5d..8c4a63110e8 100644 --- a/packages/manager/cypress/e2e/core/objectStorageMulticluster/access-keys-multicluster.spec.ts +++ b/packages/manager/cypress/e2e/core/objectStorageMulticluster/access-keys-multicluster.spec.ts @@ -259,9 +259,9 @@ describe('Object Storage Multicluster access keys', () => { ) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Permissions').click(); }); - ui.actionMenuItem.findByTitle('Permissions').click(); ui.drawer .findByTitle(`Permissions for ${mockAccessKey.label}`) .should('be.visible') diff --git a/packages/manager/cypress/e2e/core/stackscripts/delete-stackscripts.spec.ts b/packages/manager/cypress/e2e/core/stackscripts/delete-stackscripts.spec.ts index cd0aef158e3..ad28bddbf2b 100644 --- a/packages/manager/cypress/e2e/core/stackscripts/delete-stackscripts.spec.ts +++ b/packages/manager/cypress/e2e/core/stackscripts/delete-stackscripts.spec.ts @@ -35,8 +35,9 @@ describe('Delete stackscripts', () => { .findByTitle(`Action menu for StackScript ${stackScripts[0].label}`) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); }); - ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); + cy.wait('@getStackScript'); ui.dialog .findByTitle(`Delete StackScript ${stackScripts[0].label}?`) @@ -53,6 +54,11 @@ describe('Delete stackscripts', () => { }); // The StackScript is deleted successfully. + mockDeleteStackScript(stackScripts[0].id).as('deleteStackScript'); + mockGetStackScripts([stackScripts[1]]).as('getUpdatedStackScripts'); + mockGetStackScript(stackScripts[1].id, stackScripts[1]).as( + 'getUpdatedStackScript' + ); cy.get(`[data-qa-table-row="${stackScripts[0].label}"]`) .closest('tr') .within(() => { @@ -60,13 +66,9 @@ describe('Delete stackscripts', () => { .findByTitle(`Action menu for StackScript ${stackScripts[0].label}`) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); }); - mockDeleteStackScript(stackScripts[0].id).as('deleteStackScript'); - mockGetStackScripts([stackScripts[1]]).as('getUpdatedStackScripts'); - mockGetStackScript(stackScripts[1].id, stackScripts[1]).as( - 'getUpdatedStackScript' - ); - ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); + ui.dialog .findByTitle(`Delete StackScript ${stackScripts[0].label}?`) .should('be.visible') @@ -76,11 +78,12 @@ describe('Delete stackscripts', () => { .should('be.visible') .click(); }); - cy.wait('@deleteStackScript'); - cy.wait('@getUpdatedStackScripts'); + cy.wait(['@deleteStackScript', '@getUpdatedStackScripts']); cy.findByText(stackScripts[0].label).should('not.exist'); // The "Automate Deployment with StackScripts!" welcome page appears when no StackScript exists. + mockDeleteStackScript(stackScripts[1].id).as('deleteStackScript'); + mockGetStackScripts([]).as('getUpdatedStackScripts'); cy.get(`[data-qa-table-row="${stackScripts[1].label}"]`) .closest('tr') .within(() => { @@ -88,10 +91,9 @@ describe('Delete stackscripts', () => { .findByTitle(`Action menu for StackScript ${stackScripts[1].label}`) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); }); - mockDeleteStackScript(stackScripts[1].id).as('deleteStackScript'); - mockGetStackScripts([]).as('getUpdatedStackScripts'); - ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); + cy.wait('@getUpdatedStackScript'); ui.dialog .findByTitle(`Delete StackScript ${stackScripts[1].label}?`) diff --git a/packages/manager/cypress/e2e/core/stackscripts/update-stackscripts.spec.ts b/packages/manager/cypress/e2e/core/stackscripts/update-stackscripts.spec.ts index f3bee63a668..e44b741e5ce 100644 --- a/packages/manager/cypress/e2e/core/stackscripts/update-stackscripts.spec.ts +++ b/packages/manager/cypress/e2e/core/stackscripts/update-stackscripts.spec.ts @@ -117,16 +117,17 @@ describe('Update stackscripts', () => { cy.visitWithLogin('/stackscripts/account'); cy.wait('@getStackScripts'); + mockGetStackScript(stackScripts[0].id, stackScripts[0]).as( + 'getStackScript' + ); cy.get(`[data-qa-table-row="${stackScripts[0].label}"]`).within(() => { ui.actionMenu .findByTitle(`Action menu for StackScript ${stackScripts[0].label}`) .should('be.visible') .click(); + ui.actionMenuItem.findByTitle('Edit').should('be.visible').click(); }); - mockGetStackScript(stackScripts[0].id, stackScripts[0]).as( - 'getStackScript' - ); - ui.actionMenuItem.findByTitle('Edit').should('be.visible').click(); + cy.wait('@getStackScript'); cy.url().should('endWith', `/stackscripts/${stackScripts[0].id}/edit`); diff --git a/packages/manager/cypress/support/ui/action-menu.ts b/packages/manager/cypress/support/ui/action-menu.ts index 92d27c4fe3d..d93073671ef 100644 --- a/packages/manager/cypress/support/ui/action-menu.ts +++ b/packages/manager/cypress/support/ui/action-menu.ts @@ -30,12 +30,15 @@ export const actionMenuItem = { * cy.get(...).within(() => {})), the action menu item may not be found. * * @param menuItemTitle - Title of the action menu item to find. + * @param options - Additional options for the selector matcher. * * @returns Cypress chainable. */ findByTitle: (menuItemTitle: string): Cypress.Chainable => { return cy - .get('[data-qa-action-menu]') + .document() + .its('body') + .find('[data-qa-action-menu]') .should('be.visible') .find(`[data-qa-action-menu-item="${menuItemTitle}"]`) .should('be.visible');