Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
test(files): Make scrolling tests independent from magic values
Signed-off-by: Ferdinand Thiessen <[email protected]>
  • Loading branch information
susnux authored and AndyScherzinger committed Feb 6, 2025
commit 5c2cb2df9c689be3510597f2f1ddf88b1c7438eb
40 changes: 40 additions & 0 deletions cypress/e2e/core-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,43 @@ export enum UnifiedSearchFilter {
export function getUnifiedSearchFilter(filter: UnifiedSearchFilter) {
return getUnifiedSearchModal().find(`[data-cy-unified-search-filters] [data-cy-unified-search-filter="${CSS.escape(filter)}"]`)
}

/**
* Assertion that an element is fully within the current viewport.
* @param $el The element
* @param expected If the element is expected to be fully in viewport or not fully
* @example
* ```js
* cy.get('#my-element')
* .should(beFullyInViewport)
* ```
*/
export function beFullyInViewport($el: JQuery<HTMLElement>, expected = true) {
const { top, left, bottom, right } = $el.get(0)!.getBoundingClientRect()
const innerHeight = Cypress.$('body').innerHeight()!
const innerWidth = Cypress.$('body').innerWidth()!
const fullyVisible = top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth

console.debug(`fullyVisible: ${fullyVisible}, top: ${top >= 0}, left: ${left >= 0}, bottom: ${bottom <= innerHeight}, right: ${right <= innerWidth}`)

if (expected) {
// eslint-disable-next-line no-unused-expressions
expect(fullyVisible, 'Fully within viewport').to.be.true
} else {
// eslint-disable-next-line no-unused-expressions
expect(fullyVisible, 'Not fully within viewport').to.be.false
}
}

/**
* Opposite of `beFullyInViewport` - resolves when element is not or only partially in viewport.
* @param $el The element
* @example
* ```js
* cy.get('#my-element')
* .should(notBeFullyInViewport)
* ```
*/
export function notBeFullyInViewport($el: JQuery<HTMLElement>) {
return beFullyInViewport($el, false)
}
44 changes: 43 additions & 1 deletion cypress/e2e/files/FilesUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import type { User } from "@nextcloud/cypress"
import type { User } from '@nextcloud/cypress'

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)}"]`)
Expand Down Expand Up @@ -214,3 +214,45 @@ export const reloadCurrentFolder = () => {
cy.get('[data-cy-files-content-breadcrumbs]').findByRole('button', { description: 'Reload current directory' }).click()
cy.wait('@propfind')
}

/**
* Enable the grid mode for the files list.
* Will fail if already enabled!
*/
export function enableGridMode() {
cy.intercept('**/apps/files/api/v1/config/grid_view').as('setGridMode')
cy.findByRole('button', { name: 'Switch to grid view' })
.should('be.visible')
.click()
cy.wait('@setGridMode')
}

/**
* Calculate the needed viewport height to limit the visible rows of the file list.
* Requires a logged in user.
*
* @param rows The number of rows that should be displayed at the same time
*/
export function calculateViewportHeight(rows: number): Cypress.Chainable<number> {
cy.visit('/apps/files')

return cy.get('[data-cy-files-list]')
.should('be.visible')
.then((filesList) => {
const windowHeight = Cypress.$('body').outerHeight()!
// Size of other page elements
const outerHeight = Math.ceil(windowHeight - filesList.outerHeight()!)
// Size of before and filters
const beforeHeight = Math.ceil(Cypress.$('.files-list__before').outerHeight()!)
const filterHeight = Math.ceil(Cypress.$('.files-list__filters').outerHeight()!)
// Size of the table header
const tableHeaderHeight = Math.ceil(Cypress.$('[data-cy-files-list-thead]').outerHeight()!)
// table row height
const rowHeight = Math.ceil(Cypress.$('[data-cy-files-list-tbody] tr').outerHeight()!)

// sum it up
const viewportHeight = outerHeight + beforeHeight + filterHeight + tableHeaderHeight + rows * rowHeight
cy.log(`Calculated viewport height: ${viewportHeight} (${outerHeight} + ${beforeHeight} + ${filterHeight} + ${tableHeaderHeight} + ${rows} * ${rowHeight})`)
return cy.wrap(viewportHeight)
})
}
69 changes: 40 additions & 29 deletions cypress/e2e/files/files-renaming.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@
*/

import type { User } from '@nextcloud/cypress'
import { getRowForFile, haveValidity, renameFile, triggerActionForFile } from './FilesUtils'
import { calculateViewportHeight, getRowForFile, haveValidity, renameFile, triggerActionForFile } from './FilesUtils'

describe('files: Rename nodes', { testIsolation: true }, () => {
let user: User

beforeEach(() => cy.createRandomUser().then(($user) => {
user = $user

// remove welcome file
cy.rm(user, '/welcome.txt')
// create a file called "file.txt"
cy.uploadContent(user, new Blob([]), 'text/plain', '/file.txt')

// login and visit files app
cy.login(user)
cy.visit('/apps/files')
}))
Expand Down Expand Up @@ -116,34 +121,6 @@ describe('files: Rename nodes', { testIsolation: true }, () => {
.should('not.exist')
})

/**
* This is a regression test of: https://github.com/nextcloud/server/issues/47438
* The issue was that the renaming state was not reset when the new name moved the file out of the view of the current files list
* due to virtual scrolling the renaming state was not changed then by the UI events (as the component was taken out of DOM before any event handling).
*/
it('correctly resets renaming state', () => {
for (let i = 1; i <= 20; i++) {
cy.uploadContent(user, new Blob([]), 'text/plain', `/file${i}.txt`)
}
cy.viewport(1200, 500) // 500px is smaller then 20 * 50 which is the place that the files take up
cy.login(user)
cy.visit('/apps/files')

getRowForFile('file.txt').should('be.visible')
// Z so it is shown last
renameFile('file.txt', 'zzz.txt')
// not visible any longer
getRowForFile('zzz.txt').should('not.be.visible')
// scroll file list to bottom
cy.get('[data-cy-files-list]').scrollTo('bottom')
cy.screenshot()
// The file is no longer in rename state
getRowForFile('zzz.txt')
.should('be.visible')
.findByRole('textbox', { name: 'Filename' })
.should('not.exist')
})

it('cancel renaming on esc press', () => {
// All are visible by default
getRowForFile('file.txt').should('be.visible')
Expand Down Expand Up @@ -182,4 +159,38 @@ describe('files: Rename nodes', { testIsolation: true }, () => {
.find('input[type="text"]')
.should('not.exist')
})

/**
* This is a regression test of: https://github.com/nextcloud/server/issues/47438
* The issue was that the renaming state was not reset when the new name moved the file out of the view of the current files list
* due to virtual scrolling the renaming state was not changed then by the UI events (as the component was taken out of DOM before any event handling).
*/
it('correctly resets renaming state', () => {
// Create 19 additional files
for (let i = 1; i <= 19; i++) {
cy.uploadContent(user, new Blob([]), 'text/plain', `/file${i}.txt`)
}

// Calculate and setup a viewport where only the first 4 files are visible, causing 6 rows to be rendered
cy.viewport(768, 500)
cy.login(user)
calculateViewportHeight(4)
.then((height) => cy.viewport(768, height))

cy.visit('/apps/files')

getRowForFile('file.txt').should('be.visible')
// Z so it is shown last
renameFile('file.txt', 'zzz.txt')
// not visible any longer
getRowForFile('zzz.txt').should('not.exist')
// scroll file list to bottom
cy.get('[data-cy-files-list]').scrollTo('bottom')
cy.screenshot()
// The file is no longer in rename state
getRowForFile('zzz.txt')
.should('be.visible')
.findByRole('textbox', { name: 'Filename' })
.should('not.exist')
})
})
Loading