Skip to content

fix(cypress): use atomic cy.get() selectors to prevent detached DOM flakiness#60324

Draft
skjnldsv wants to merge 1 commit into
nextcloud:masterfrom
skjnldsv:fix/cypress-atomic-file-list-selectors
Draft

fix(cypress): use atomic cy.get() selectors to prevent detached DOM flakiness#60324
skjnldsv wants to merge 1 commit into
nextcloud:masterfrom
skjnldsv:fix/cypress-atomic-file-list-selectors

Conversation

@skjnldsv
Copy link
Copy Markdown
Member

Summary

  • Replace all chained .find() / .findByRole() calls on file-list row subjects with single atomic cy.get() compound selectors
  • When Vue re-renders the file list (e.g. while opening the sharing sidebar), Cypress throws "subject no longer attached to the DOM" on any chained .find() — the engine cannot re-query through a chained command; a root-level cy.get() is re-executed from scratch on every retry
  • Removes duplicate getActionButtonForFile() call in triggerActionForFile/Id; adds force: true on menu item click for animation robustness

Key changes in cypress/e2e/files/FilesUtils.ts

Function Before After
getActionButtonForFile/Id getActionsFor*().findByRole('button', { name: 'Actions' }) cy.get('... button[aria-label="Actions"]')
getActionEntryForFile/Id cy.get('#id').should('exist').find(child) cy.get('#id child') combined selector
triggerActionForFile/Id getActionEntryForFile().find('button') cy.get('[role="menu"] [data-cy-...] > button')
triggerInlineActionFor* getActionsFor*().find('button[data-cy...]') atomic cy.get()
selectRowForFile getRowForFile().find().findByRole() cy.get('... input[type="checkbox"]')
renameFile getRowForFile().find('[data-cy-files-list-row-name] input') atomic cy.get()
navigateToFolder getRowForFile().find('[data-cy-files-list-row-name-link]') atomic cy.get()

Note: NcActions default ariaLabel is t('Actions') (confirmed in @nextcloud/vue source). aria-controls is only set while the menu is opengetActionEntryForFile/Id (which use it) are only called by tests that explicitly open the menu first, so they remain correct.

Fixes recurring CI failures in

  • cypress/e2e/files/files-renaming.cy.ts — "shows warning on extension change", "shows warning on extension removal", "does not show warning on folder renaming with a dot"
  • cypress/e2e/files_sharing/note-to-recipient.cy.ts — "displays the note to the sharee even if the file list is empty", "shows an existing note when editing a share"
  • cypress/e2e/files/favorites.cy.ts — "See favorite folders in navigation", "Mark file as favorite using the sidebar"

Test plan

  • Run cypress/e2e/files/files-renaming.cy.ts multiple times — no "subject no longer attached" errors
  • Run cypress/e2e/files_sharing/note-to-recipient.cy.ts — all tests pass
  • Run cypress/e2e/files/favorites.cy.ts — all tests pass
  • Run cypress/e2e/files/files-actions.cy.tsgetActionEntryForFileId still works (opens menu first)
  • Run cypress/e2e/files_sharing/files-download.cy.tsgetActionEntryForFile still works for .should('not.exist') assertions

🤖 Generated with Claude Code

@skjnldsv skjnldsv requested a review from a team as a code owner May 12, 2026 10:03
@skjnldsv skjnldsv requested review from nfebe, sorbaugh and susnux and removed request for a team May 12, 2026 10:03
@skjnldsv skjnldsv added bug 2. developing Work in progress tests Related to tests labels May 12, 2026
@skjnldsv skjnldsv closed this May 12, 2026
@skjnldsv skjnldsv reopened this May 12, 2026
…lakiness

All file-list helper functions now use a single cy.get() with a compound
CSS selector from the document root instead of chaining .find() /
.findByRole() on an intermediate subject.

When Vue re-renders the file list (e.g. while opening the sharing sidebar)
Cypress throws "subject no longer attached to the DOM" on any chained
.find() call — the engine cannot re-query through a chained command.
A single cy.get() with a compound selector is re-executed from scratch
on every assertion retry, making it immune to mid-render detachment.

Changes:
- getActionButtonForFile/Id: use button[aria-label="Actions"] atomic selector
  (NcActions default ariaLabel is t('Actions') per @nextcloud/vue source)
- getActionEntryForFile/Id: combine #menuId + descendant in one cy.get()
  instead of cy.get('#id').find(child)
- triggerActionForFile/Id: single trigger click + atomic
  [role="menu"] [data-cy-files-list-row-action="id"] > button query;
  removes duplicate getActionButtonForFile() call; adds force:true on
  menu item click for animation/overlay robustness
- triggerInlineActionForFile/Id: atomic row selector instead of
  getActionsFor*().find()
- selectRowForFile: atomic row+checkbox input selector
- renameFile: atomic row+name-cell+input selector
- navigateToFolder: atomic row+name-link selector

Fixes the recurring CI failures in:
  cypress/e2e/files/files-renaming.cy.ts
  cypress/e2e/files_sharing/note-to-recipient.cy.ts
  cypress/e2e/files/favorites.cy.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@skjnldsv skjnldsv force-pushed the fix/cypress-atomic-file-list-selectors branch from c61113c to 9a43669 Compare May 12, 2026 10:05
@skjnldsv skjnldsv marked this pull request as draft May 12, 2026 12:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2. developing Work in progress bug tests Related to tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant