diff --git a/cypress/e2e/files/FilesUtils.ts b/cypress/e2e/files/FilesUtils.ts index 9ae1ee31f3552..2d7a28ac6d677 100644 --- a/cypress/e2e/files/FilesUtils.ts +++ b/cypress/e2e/files/FilesUtils.ts @@ -10,8 +10,10 @@ const ACTION_COPY_MOVE = 'move-copy' export const getRowForFileId = (fileid: string | number) => cy.get(`[data-cy-files-list-row-fileid="${fileid}"]`) export const getRowForFile = (filename: string) => cy.get(`[data-cy-files-list-row-name="${CSS.escape(filename)}"]`) -export const getActionsForFileId = (fileid: number) => getRowForFileId(fileid).find('[data-cy-files-list-row-actions]') -export const getActionsForFile = (filename: string) => getRowForFile(filename).find('[data-cy-files-list-row-actions]') +// Atomic query so the lookup is retried as a whole when rows re-render +// (chained .find() can fail with "subject no longer attached" mid-render). +export const getActionsForFileId = (fileid: number) => cy.get(`[data-cy-files-list-row-fileid="${fileid}"] [data-cy-files-list-row-actions]`) +export const getActionsForFile = (filename: string) => cy.get(`[data-cy-files-list-row-name="${CSS.escape(filename)}"] [data-cy-files-list-row-actions]`) export const getActionButtonForFileId = (fileid: number) => getActionsForFileId(fileid).findByRole('button', { name: 'Actions' }) export const getActionButtonForFile = (filename: string) => getActionsForFile(filename).findByRole('button', { name: 'Actions' }) @@ -48,8 +50,7 @@ export function getActionEntryForFile(file: string, actionId: string) { * @param actionId */ export function getInlineActionEntryForFileId(fileid: number, actionId: string) { - return getActionsForFileId(fileid) - .find(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`) + return cy.get(`[data-cy-files-list-row-fileid="${fileid}"] [data-cy-files-list-row-action="${CSS.escape(actionId)}"]`) } /** @@ -58,8 +59,7 @@ export function getInlineActionEntryForFileId(fileid: number, actionId: string) * @param actionId */ export function getInlineActionEntryForFile(file: string, actionId: string) { - return getActionsForFile(file) - .find(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`) + return cy.get(`[data-cy-files-list-row-name="${CSS.escape(file)}"] [data-cy-files-list-row-action="${CSS.escape(actionId)}"]`) } /** diff --git a/cypress/e2e/files/files-delete.cy.ts b/cypress/e2e/files/files-delete.cy.ts index 8d51e82de34aa..b1af310d9b6dd 100644 --- a/cypress/e2e/files/files-delete.cy.ts +++ b/cypress/e2e/files/files-delete.cy.ts @@ -5,7 +5,7 @@ import type { User } from '@nextcloud/e2e-test-server/cypress' -import { getRowForFile, navigateToFolder, selectAllFiles, triggerActionForFile } from './FilesUtils.ts' +import { getRowForFile, navigateToFolder, selectAllFiles, triggerActionForFile, triggerSelectionAction } from './FilesUtils.ts' describe('files: Delete files using file actions', { testIsolation: true }, () => { let user: User @@ -50,12 +50,7 @@ describe('files: Delete files using file actions', { testIsolation: true }, () = // select all selectAllFiles() - cy.get('[data-cy-files-list-selection-actions]') - .findByRole('button', { name: 'Actions' }) - .click() - cy.get('[data-cy-files-list-selection-action="delete"]') - .findByRole('menuitem', { name: /^Delete files/ }) - .click() + triggerSelectionAction('delete') // see dialog for confirmation cy.findByRole('dialog', { name: 'Confirm deletion' }) diff --git a/cypress/e2e/files/files-download.cy.ts b/cypress/e2e/files/files-download.cy.ts index 7e74f7a8b8c20..c811a4a4a8ed4 100644 --- a/cypress/e2e/files/files-download.cy.ts +++ b/cypress/e2e/files/files-download.cy.ts @@ -8,7 +8,7 @@ import type { User } from '@nextcloud/e2e-test-server/cypress' import { zipFileContains } from '../../support/utils/assertions.ts' import { deleteDownloadsFolderBeforeEach } from '../../support/utils/deleteDownloadsFolder.ts' import { randomString } from '../../support/utils/randomString.ts' -import { getRowForFile, navigateToFolder, triggerActionForFile } from './FilesUtils.ts' +import { getRowForFile, navigateToFolder, triggerActionForFile, triggerSelectionAction } from './FilesUtils.ts' describe('files: Download files using file actions', { testIsolation: true }, () => { let user: User @@ -194,12 +194,7 @@ describe('files: Download files using selection', () => { }) // click download - cy.get('[data-cy-files-list-selection-actions]') - .findByRole('button', { name: 'Actions' }) - .click() - cy.findByRole('menuitem', { name: 'Download (selected)' }) - .should('be.visible') - .click() + triggerSelectionAction('download') // check a file is downloaded const downloadsFolder = Cypress.config('downloadsFolder') @@ -237,11 +232,7 @@ describe('files: Download files using selection', () => { }) // click download - cy.get('[data-cy-files-list-selection-actions]') - .findByRole('button', { name: 'Actions' }) - .click() - cy.findByRole('menuitem', { name: 'Download (selected)' }) - .click() + triggerSelectionAction('download') // check a file is downloaded const downloadsFolder = Cypress.config('downloadsFolder') @@ -282,11 +273,7 @@ describe('files: Download files using selection', () => { }) // click download - cy.get('[data-cy-files-list-selection-actions]') - .findByRole('button', { name: 'Actions' }) - .click() - cy.findByRole('menuitem', { name: 'Download (selected)' }) - .click() + triggerSelectionAction('download') // check a file is downloaded const downloadsFolder = Cypress.config('downloadsFolder') @@ -330,11 +317,7 @@ describe('files: Download files using selection', () => { }) // click download - cy.get('[data-cy-files-list-selection-actions]') - .findByRole('button', { name: 'Actions' }) - .click() - cy.findByRole('menuitem', { name: 'Download (selected)' }) - .click() + triggerSelectionAction('download') // check a file is downloaded const downloadsFolder = Cypress.config('downloadsFolder') diff --git a/cypress/e2e/files_sharing/share-status-action.cy.ts b/cypress/e2e/files_sharing/share-status-action.cy.ts index cfbbc29664bd3..30a76334b091c 100644 --- a/cypress/e2e/files_sharing/share-status-action.cy.ts +++ b/cypress/e2e/files_sharing/share-status-action.cy.ts @@ -4,7 +4,7 @@ */ import type { User } from '@nextcloud/e2e-test-server/cypress' -import { closeSidebar, enableGridMode, getActionButtonForFile, getInlineActionEntryForFile, getRowForFile } from '../files/FilesUtils.ts' +import { closeSidebar, enableGridMode, getActionButtonForFile, getActionsForFile, getInlineActionEntryForFile, getRowForFile } from '../files/FilesUtils.ts' import { createShare } from './FilesSharingUtils.ts' describe('files_sharing: Sharing status action', { testIsolation: true }, () => { @@ -23,9 +23,8 @@ describe('files_sharing: Sharing status action', { testIsolation: true }, () => cy.visit('/apps/files') - getRowForFile('folder') - .should('be.visible') - .find('[data-cy-files-list-row-actions]') + getRowForFile('folder').should('be.visible') + getActionsForFile('folder') .findByRole('button', { name: 'Shared' }) .should('not.exist') }) @@ -38,12 +37,11 @@ describe('files_sharing: Sharing status action', { testIsolation: true }, () => cy.visit('/apps/files') }) - getRowForFile('folder') - .should('be.visible') - .find('[data-cy-files-list-row-actions]') + getRowForFile('folder').should('be.visible') + getActionsForFile('folder') .findByRole('button', { name: /Sharing options/ }) .should('be.visible') - .click() + .click({ force: true }) // check the click opened the sidebar cy.get('[data-cy-sidebar]') diff --git a/cypress/e2e/files_versions/version_restoration.cy.ts b/cypress/e2e/files_versions/version_restoration.cy.ts index 7ece6d7959f89..2d7e66068d90a 100644 --- a/cypress/e2e/files_versions/version_restoration.cy.ts +++ b/cypress/e2e/files_versions/version_restoration.cy.ts @@ -69,7 +69,7 @@ describe('Versions restoration', () => { cy.get('[data-files-versions-version]').eq(0).find('.action-item__menutoggle').should('not.exist') cy.get('[data-files-versions-version]').eq(0).get('[data-cy-version-action="restore"]').should('not.exist') - doesNotHaveAction(1, 'restore') doesNotHaveAction(2, 'restore') + doesNotHaveAction(1, 'restore') }) })