From 70522c2d3d77cacd806b880e1b4437f0222989ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Mon, 11 May 2026 11:07:13 +0200 Subject: [PATCH 1/4] chore(ci): Use the proper helper function to trigger action on selected rows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- cypress/e2e/files/files-delete.cy.ts | 7 +------ cypress/e2e/files/files-download.cy.ts | 25 ++++--------------------- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/cypress/e2e/files/files-delete.cy.ts b/cypress/e2e/files/files-delete.cy.ts index edb88519c59..1225b332413 100644 --- a/cypress/e2e/files/files-delete.cy.ts +++ b/cypress/e2e/files/files-delete.cy.ts @@ -49,12 +49,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 06eb62094b8..50ec1ccde43 100644 --- a/cypress/e2e/files/files-download.cy.ts +++ b/cypress/e2e/files/files-download.cy.ts @@ -195,12 +195,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') @@ -238,11 +233,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') @@ -283,11 +274,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') @@ -331,11 +318,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') From beee7427c5a11d5a4d97830bd7a89c9477b7d8a8 Mon Sep 17 00:00:00 2001 From: Peter Ringelmann Date: Mon, 11 May 2026 13:15:18 +0200 Subject: [PATCH 2/4] chore(ci): Make row action helpers atomic to avoid mid-render detachment -e Signed-off-by: Peter Ringelmann --- cypress/e2e/files/FilesUtils.ts | 6 ++++-- cypress/e2e/files_sharing/share-status-action.cy.ts | 12 +++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cypress/e2e/files/FilesUtils.ts b/cypress/e2e/files/FilesUtils.ts index 70767b5ecf1..8bc5ffc7067 100644 --- a/cypress/e2e/files/FilesUtils.ts +++ b/cypress/e2e/files/FilesUtils.ts @@ -9,8 +9,10 @@ import { ACTION_COPY_MOVE } from '../../../apps/files/src/actions/moveOrCopyActi export const getRowForFileId = (fileid: 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' }) diff --git a/cypress/e2e/files_sharing/share-status-action.cy.ts b/cypress/e2e/files_sharing/share-status-action.cy.ts index f02ec676573..9dd072cc210 100644 --- a/cypress/e2e/files_sharing/share-status-action.cy.ts +++ b/cypress/e2e/files_sharing/share-status-action.cy.ts @@ -22,9 +22,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') }) @@ -37,12 +36,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]') From 37270db58396011d2af9046c48785f8d9e7efdcf Mon Sep 17 00:00:00 2001 From: Peter Ringelmann Date: Tue, 12 May 2026 10:47:44 +0200 Subject: [PATCH 3/4] test(cypress): import missing triggerSelectionAction helper Signed-off-by: Peter Ringelmann --- cypress/e2e/files/files-delete.cy.ts | 2 +- cypress/e2e/files/files-download.cy.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/files/files-delete.cy.ts b/cypress/e2e/files/files-delete.cy.ts index 1225b332413..d7fd0ccb811 100644 --- a/cypress/e2e/files/files-delete.cy.ts +++ b/cypress/e2e/files/files-delete.cy.ts @@ -4,7 +4,7 @@ */ import type { User } from '@nextcloud/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 diff --git a/cypress/e2e/files/files-download.cy.ts b/cypress/e2e/files/files-download.cy.ts index 50ec1ccde43..f51dca18a17 100644 --- a/cypress/e2e/files/files-download.cy.ts +++ b/cypress/e2e/files/files-download.cy.ts @@ -4,7 +4,7 @@ */ import type { User } from '@nextcloud/cypress' -import { getRowForFile, navigateToFolder, triggerActionForFile } from './FilesUtils' +import { getRowForFile, navigateToFolder, triggerActionForFile, triggerSelectionAction } from './FilesUtils' import { deleteDownloadsFolderBeforeEach } from 'cypress-delete-downloads-folder' import { zipFileContains } from '../../support/utils/assertions.ts' From f5b01a3e66a4a9644d6e86357658108618e7a111 Mon Sep 17 00:00:00 2001 From: Peter Ringelmann Date: Tue, 12 May 2026 15:24:48 +0200 Subject: [PATCH 4/4] test(cypress): keep inline selection-action clicks on stable32 Signed-off-by: Peter Ringelmann --- cypress/e2e/files/files-delete.cy.ts | 9 +++++-- cypress/e2e/files/files-download.cy.ts | 27 +++++++++++++++---- .../files_sharing/share-status-action.cy.ts | 2 +- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/cypress/e2e/files/files-delete.cy.ts b/cypress/e2e/files/files-delete.cy.ts index d7fd0ccb811..edb88519c59 100644 --- a/cypress/e2e/files/files-delete.cy.ts +++ b/cypress/e2e/files/files-delete.cy.ts @@ -4,7 +4,7 @@ */ import type { User } from '@nextcloud/cypress' -import { getRowForFile, navigateToFolder, selectAllFiles, triggerActionForFile, triggerSelectionAction } from './FilesUtils.ts' +import { getRowForFile, navigateToFolder, selectAllFiles, triggerActionForFile } from './FilesUtils.ts' describe('files: Delete files using file actions', { testIsolation: true }, () => { let user: User @@ -49,7 +49,12 @@ describe('files: Delete files using file actions', { testIsolation: true }, () = // select all selectAllFiles() - triggerSelectionAction('delete') + 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() // 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 f51dca18a17..06eb62094b8 100644 --- a/cypress/e2e/files/files-download.cy.ts +++ b/cypress/e2e/files/files-download.cy.ts @@ -4,7 +4,7 @@ */ import type { User } from '@nextcloud/cypress' -import { getRowForFile, navigateToFolder, triggerActionForFile, triggerSelectionAction } from './FilesUtils' +import { getRowForFile, navigateToFolder, triggerActionForFile } from './FilesUtils' import { deleteDownloadsFolderBeforeEach } from 'cypress-delete-downloads-folder' import { zipFileContains } from '../../support/utils/assertions.ts' @@ -195,7 +195,12 @@ describe('files: Download files using selection', () => { }) // click download - triggerSelectionAction('download') + cy.get('[data-cy-files-list-selection-actions]') + .findByRole('button', { name: 'Actions' }) + .click() + cy.findByRole('menuitem', { name: 'Download (selected)' }) + .should('be.visible') + .click() // check a file is downloaded const downloadsFolder = Cypress.config('downloadsFolder') @@ -233,7 +238,11 @@ describe('files: Download files using selection', () => { }) // click download - triggerSelectionAction('download') + cy.get('[data-cy-files-list-selection-actions]') + .findByRole('button', { name: 'Actions' }) + .click() + cy.findByRole('menuitem', { name: 'Download (selected)' }) + .click() // check a file is downloaded const downloadsFolder = Cypress.config('downloadsFolder') @@ -274,7 +283,11 @@ describe('files: Download files using selection', () => { }) // click download - triggerSelectionAction('download') + cy.get('[data-cy-files-list-selection-actions]') + .findByRole('button', { name: 'Actions' }) + .click() + cy.findByRole('menuitem', { name: 'Download (selected)' }) + .click() // check a file is downloaded const downloadsFolder = Cypress.config('downloadsFolder') @@ -318,7 +331,11 @@ describe('files: Download files using selection', () => { }) // click download - triggerSelectionAction('download') + cy.get('[data-cy-files-list-selection-actions]') + .findByRole('button', { name: 'Actions' }) + .click() + cy.findByRole('menuitem', { name: 'Download (selected)' }) + .click() // 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 9dd072cc210..4c07a635900 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/cypress' import { createShare } from './FilesSharingUtils.ts' -import { closeSidebar, enableGridMode, getActionButtonForFile, getInlineActionEntryForFile, getRowForFile } from '../files/FilesUtils.ts' +import { closeSidebar, enableGridMode, getActionButtonForFile, getActionsForFile, getInlineActionEntryForFile, getRowForFile } from '../files/FilesUtils.ts' describe('files_sharing: Sharing status action', { testIsolation: true }, () => { /**