From 0c54d519355f73b032eb32330a87505fe13ebdf6 Mon Sep 17 00:00:00 2001 From: Josh Date: Sat, 21 Mar 2026 11:34:07 -0400 Subject: [PATCH] test(cypress): improve resilience of files-copy-move sharing tests - Remove `.within()` scoping to avoid stale DOM references on re-render - Remove unused `cy.intercept()` calls (aliases were never awaited) - Add explicit visibility gates before file picker interactions - Re-query `.file-picker` per command chain for DOM freshness - Add `CSS.escape()` to `moveFileForbidden` directory selector (bug fix) - Increase assertion timeouts for slow CI environments - Replace `cy.contains().should('not.exist')` anti-pattern with `cy.get().should('not.contain')` for correct negative assertion Signed-off-by: Josh --- .../e2e/files_sharing/files-copy-move.cy.ts | 60 +++++++++++-------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/cypress/e2e/files_sharing/files-copy-move.cy.ts b/cypress/e2e/files_sharing/files-copy-move.cy.ts index 16d07c3d40c20..7c0272248d309 100644 --- a/cypress/e2e/files_sharing/files-copy-move.cy.ts +++ b/cypress/e2e/files_sharing/files-copy-move.cy.ts @@ -19,44 +19,52 @@ export function copyFileForbidden(fileName: string, dirPath: string) { getRowForFile(fileName).should('be.visible') triggerActionForFile(fileName, ACTION_COPY_MOVE) - cy.get('.file-picker').within(() => { - // intercept the copy so we can wait for it - cy.intercept('COPY', /\/(remote|public)\.php\/dav\/files\//).as('copyFile') - - const directories = dirPath.split('/') - directories.forEach((directory) => { - // select the folder - cy.get(`[data-filename="${CSS.escape(directory)}"]`).should('be.visible').click() - }) + cy.get('.file-picker').should('be.visible') - // check copy button - cy.contains('button', `Copy to ${directories.at(-1)}`).should('be.disabled') + const directories = dirPath.split('/') + directories.forEach((directory) => { + cy.get('.file-picker') + .find(`[data-filename="${CSS.escape(directory)}"]`) + .should('be.visible') + .click() }) + + // Re-query after possible re-render and assert eventual disabled state + cy.get('.file-picker') + .contains('button', `Copy to ${directories.at(-1)}`, { timeout: 10000 }) + .should('be.visible') + .and('be.disabled') } export function moveFileForbidden(fileName: string, dirPath: string) { getRowForFile(fileName).should('be.visible') triggerActionForFile(fileName, ACTION_COPY_MOVE) - cy.get('.file-picker').within(() => { - // intercept the copy so we can wait for it - cy.intercept('MOVE', /\/(remote|public)\.php\/dav\/files\//).as('moveFile') + cy.get('.file-picker').should('be.visible') - // select home folder - cy.get('.breadcrumb') - .findByRole('button', { name: 'All files' }) - .should('be.visible') - .click() + // Avoid stale chained subject when breadcrumb re-renders + cy.get('.file-picker .breadcrumb') + .findByRole('button', { name: 'All files' }) + .should('be.visible') + .click() - const directories = dirPath.split('/') - directories.forEach((directory) => { - // select the folder - cy.get(`[data-filename="${directory}"]`).should('be.visible').click() - }) + // Re-acquire file picker after navigation click + cy.get('.file-picker').should('be.visible') - // click move - cy.contains('button', `Move to ${directories.at(-1)}`).should('not.exist') + const directories = dirPath.split('/') + directories.forEach((directory) => { + cy.get('.file-picker') + .find(`[data-filename="${CSS.escape(directory)}"]`) + .should('be.visible') + .click() }) + + // If move is forbidden, the move button should not be present. + // Use should('not.contain') on the parent to avoid the cy.contains() + should('not.exist') + // anti-pattern, where cy.contains() must first find the element before the negation can pass, + // causing unnecessary waits or false failures. + cy.get('.file-picker', { timeout: 10000 }) + .should('not.contain', `Move to ${directories.at(-1)}`) } describe('files_sharing: Move or copy files', { testIsolation: true }, () => {