From 333572c54df13d8a8611ad793a12e4f108a3952c Mon Sep 17 00:00:00 2001 From: Anna Larch Date: Wed, 6 May 2026 11:17:12 +0200 Subject: [PATCH 1/2] test(cypress): improve e2e test stability - toggleMenuAction: use force:true on clicks and a 10s timeout for the action element to survive Vue re-renders caused by async metadata updates (e.g. share badge appearing after file list load) - sidebar.cy.ts "Has share activity": wait for the files PROPFIND to complete after cy.visit so share DAV properties are fully applied before opening the Actions menu - settings.cy.ts "Form survive a reload": intercept and wait for the settings save API before each cy.reload(), matching the pattern already used by the other two tests in this suite - createPublicShare: remove duplicate intercept alias for the same POST endpoint and the redundant trailing cy.wait() - addTag: wait for the file row preview to load before triggering the action menu, consistent with renameFile AI-Assisted-By: Claude Sonnet 4.6 Signed-off-by: Anna Larch --- cypress/e2e/filesUtils.ts | 6 +++--- cypress/e2e/settings.cy.ts | 4 ++++ cypress/e2e/sidebar.cy.ts | 4 ++++ cypress/e2e/sidebarUtils.ts | 11 ++++++----- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/cypress/e2e/filesUtils.ts b/cypress/e2e/filesUtils.ts index a81565159..20f5c79c0 100644 --- a/cypress/e2e/filesUtils.ts +++ b/cypress/e2e/filesUtils.ts @@ -130,10 +130,10 @@ export function toggleMenuAction(filename: string, action: 'details'|'favorite'| .find('[data-cy-files-list-row-actions]') .findByRole('button', { name: 'Actions' }) .should('be.visible') - .click() + .click({ force: true }) - cy.get(`[data-cy-files-list-row-action="${CSS.escape(action)}"]`) + cy.get(`[data-cy-files-list-row-action="${CSS.escape(action)}"]`, { timeout: 10000 }) .should('be.visible') .findByRole('menuitem') - .click() + .click({ force: true }) } diff --git a/cypress/e2e/settings.cy.ts b/cypress/e2e/settings.cy.ts index 49d0777d7..e3a2e99d3 100644 --- a/cypress/e2e/settings.cy.ts +++ b/cypress/e2e/settings.cy.ts @@ -19,8 +19,11 @@ describe('Check that user\'s settings survive a reload', () => { }) it('Form survive a reload', () => { + cy.intercept({ method: 'POST', url: '**/activity/settings' }).as('apiCall') + cy.get("#app-content input[type='checkbox']").uncheck({ force: true }) cy.get("#app-content input[type='checkbox']").should('not.be.checked') + cy.wait('@apiCall') cy.reload() @@ -34,6 +37,7 @@ describe('Check that user\'s settings survive a reload', () => { cy.get('#calendar_notification').check({ force: true }) cy.get('#personal_settings_email').check({ force: true }) cy.get('#personal_settings_notification').check({ force: true }) + cy.wait('@apiCall') cy.reload() cy.get('#file_changed_email').should('not.be.checked') diff --git a/cypress/e2e/sidebar.cy.ts b/cypress/e2e/sidebar.cy.ts index 14f0b0bea..4d9447c0e 100644 --- a/cypress/e2e/sidebar.cy.ts +++ b/cypress/e2e/sidebar.cy.ts @@ -38,7 +38,11 @@ describe('Check activity listing in the sidebar', { testIsolation: true }, () => it('Has share activity', () => { createPublicShare('welcome.txt') + cy.intercept('PROPFIND', /\/remote\.php\/dav\/files\//).as('loadFiles') cy.visit('/apps/files') + // Wait for the file list PROPFIND to complete — share types are returned as + // WebDAV properties in this response, so the row is stable once it resolves. + cy.wait('@loadFiles') getFileListRow('welcome.txt').should('be.visible') showActivityTab('welcome.txt') diff --git a/cypress/e2e/sidebarUtils.ts b/cypress/e2e/sidebarUtils.ts index 8194df144..f074ee2a4 100644 --- a/cypress/e2e/sidebarUtils.ts +++ b/cypress/e2e/sidebarUtils.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { toggleMenuAction, triggerActionForFile } from './filesUtils.ts' +import { getRowForFile, toggleMenuAction, triggerActionForFile } from './filesUtils.ts' function showSidebarForFile(fileName: string) { toggleMenuAction(fileName, 'details') @@ -60,8 +60,6 @@ export function toggleFavorite(fileName: string) { * @param fileName Name of the file to share */ export function createPublicShare(fileName: string) { - cy.intercept('POST', '/ocs/v2.php/apps/files_sharing/api/v1/shares').as('createPublicShare') - showSidebarForFile(fileName) cy.get('#app-sidebar-vue') .findByRole('tab', { name: 'Sharing' }) @@ -77,8 +75,6 @@ export function createPublicShare(fileName: string) { cy.wait('@createShare') closeSidebar() - - cy.wait('@createPublicShare') } /** @@ -88,6 +84,11 @@ export function createPublicShare(fileName: string) { * @param newTag - The new tag */ export function addTag(fileName: string, newTag: string) { + getRowForFile(fileName) + .should('be.visible') + .find('.files-list__row-icon-preview--loaded') + .should('exist') + triggerActionForFile(fileName, 'systemtags:bulk') cy.intercept('POST', '/remote.php/dav/systemtags').as('createTag') From c469007b3fe2f82175c37641c9e7260b03d6691b Mon Sep 17 00:00:00 2001 From: Anna Larch Date: Wed, 6 May 2026 11:39:11 +0200 Subject: [PATCH 2/2] test(cypress): fix Has share activity race condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skip the re-navigation to /apps/files after createPublicShare. The share is already recorded server-side (cy.wait('@createShare')) and the sidebar is closed, so showActivityTab can be called directly. Re-navigating caused NC to async-load the share badge on the file row, which triggered a Vue re-render that closed the Actions menu before the details entry could be clicked — failing even with a 10s timeout. AI-Assisted-By: Claude Sonnet 4.6 Signed-off-by: Anna Larch --- cypress/e2e/sidebar.cy.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/cypress/e2e/sidebar.cy.ts b/cypress/e2e/sidebar.cy.ts index 4d9447c0e..9fc3cbff4 100644 --- a/cypress/e2e/sidebar.cy.ts +++ b/cypress/e2e/sidebar.cy.ts @@ -38,13 +38,9 @@ describe('Check activity listing in the sidebar', { testIsolation: true }, () => it('Has share activity', () => { createPublicShare('welcome.txt') - cy.intercept('PROPFIND', /\/remote\.php\/dav\/files\//).as('loadFiles') - cy.visit('/apps/files') - // Wait for the file list PROPFIND to complete — share types are returned as - // WebDAV properties in this response, so the row is stable once it resolves. - cy.wait('@loadFiles') - getFileListRow('welcome.txt').should('be.visible') - + // No re-navigation needed — createPublicShare already waits for the share API + // and closes the sidebar, so the activity is recorded and the page is stable. + // Re-navigating triggers an async share-badge update that closes the Actions menu. showActivityTab('welcome.txt') cy.get('.activity-entry').first().should('contains.text', 'Shared as public link') })