Skip to content

Commit 423a91d

Browse files
committed
test(files): Make scrolling tests independent from magic values
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
1 parent d22af2a commit 423a91d

File tree

3 files changed

+96
-28
lines changed

3 files changed

+96
-28
lines changed

cypress/e2e/core-utils.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,38 @@ export enum UnifiedSearchFilter {
4848
export function getUnifiedSearchFilter(filter: UnifiedSearchFilter) {
4949
return getUnifiedSearchModal().find(`[data-cy-unified-search-filters] [data-cy-unified-search-filter="${CSS.escape(filter)}"]`)
5050
}
51+
52+
/**
53+
* Assertion that an element is fully within the current viewport.
54+
* @param $el The element
55+
* @param expected If the element is expected to be fully in viewport or not fully
56+
* @example
57+
* ```js
58+
* cy.get('#my-element')
59+
* .should(beFullyInViewport)
60+
* ```
61+
*/
62+
export function beFullyInViewport($el: JQuery<HTMLElement>, expected = true) {
63+
const { top, left, bottom, right } = $el.get(0)!.getBoundingClientRect()
64+
const { innerHeight, innerWidth } = window
65+
const fullyVisible = top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth
66+
67+
if (expected) {
68+
expect(fullyVisible, 'Fully within viewport').to.be.true
69+
} else {
70+
expect(fullyVisible, 'Not fully within viewport').to.be.false
71+
}
72+
}
73+
74+
/**
75+
* Opposite of `beFullyInViewport` - resolves when element is not or only partially in viewport.
76+
* @param $el The element
77+
* @example
78+
* ```js
79+
* cy.get('#my-element')
80+
* .should(notBeFullyInViewport)
81+
* ```
82+
*/
83+
export function notBeFullyInViewport($el: JQuery<HTMLElement>) {
84+
return beFullyInViewport($el, false)
85+
}

cypress/e2e/files/FilesUtils.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,15 @@ export const reloadCurrentFolder = () => {
214214
cy.get('[data-cy-files-content-breadcrumbs]').findByRole('button', { description: 'Reload current directory' }).click()
215215
cy.wait('@propfind')
216216
}
217+
218+
/**
219+
* Enable the grid mode for the files list.
220+
* Will fail if already enabled!
221+
*/
222+
export function enableGridMode() {
223+
cy.intercept('**/apps/files/api/v1/config/grid_view').as('setGridMode')
224+
cy.findByRole('button', { name: 'Switch to grid view' })
225+
.should('be.visible')
226+
.click()
227+
cy.wait('@setGridMode')
228+
}

cypress/e2e/files/scrolling.cy.ts

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
*/
55

66
import type { User } from '@nextcloud/cypress'
7-
import { getRowForFile } from './FilesUtils'
7+
import { enableGridMode, getRowForFile } from './FilesUtils.ts'
8+
import { notBeFullyInViewport } from '../core-utils.ts'
89

910
describe('files: Scrolling to selected file in file list', { testIsolation: true }, () => {
1011
const fileIds = new Map<number, string>()
1112
let user: User
13+
let viewportHeight: number
1214

1315
before(() => {
1416
cy.createRandomUser().then(($user) => {
@@ -19,12 +21,17 @@ describe('files: Scrolling to selected file in file list', { testIsolation: true
1921
cy.uploadContent(user, new Blob([]), 'text/plain', `/${i}.txt`)
2022
.then((response) => fileIds.set(i, Number.parseInt(response.headers['oc-fileid']).toString()))
2123
}
24+
25+
cy.login(user)
26+
cy.viewport(1200, 800)
27+
// Calculate height to ensure that those 10 elements can not be rendered in one list (only 6 will fit the screen)
28+
calculateViewportHeight(6)
29+
.then((height) => { viewportHeight = height })
2230
})
2331
})
2432

2533
beforeEach(() => {
26-
// Adjust height to ensure that those 10 elements can not be rendered in one list
27-
cy.viewport(1200, 6 * 55 /* rows */ + 55 /* table header */ + 50 /* navigation header */ + 50 /* breadcrumbs */ + 46 /* file filters */)
34+
cy.viewport(1200, viewportHeight)
2835
cy.login(user)
2936
})
3037

@@ -64,7 +71,6 @@ describe('files: Scrolling to selected file in file list', { testIsolation: true
6471
.and(beOverlappedByTableHeader)
6572
getRowForFile(`${i + 5}.txt`)
6673
.should('exist')
67-
.and('be.visible')
6874
.and(notBeFullyInViewport)
6975
})
7076
}
@@ -117,6 +123,7 @@ describe('files: Scrolling to selected file in file list', { testIsolation: true
117123
describe('files: Scrolling to selected file in file list (GRID MODE)', { testIsolation: true }, () => {
118124
const fileIds = new Map<number, string>()
119125
let user: User
126+
let viewportHeight: number
120127

121128
before(() => {
122129
cy.createRandomUser().then(($user) => {
@@ -127,21 +134,22 @@ describe('files: Scrolling to selected file in file list (GRID MODE)', { testIso
127134
cy.uploadContent(user, new Blob([]), 'text/plain', `/${i}.txt`)
128135
.then((response) => fileIds.set(i, Number.parseInt(response.headers['oc-fileid']).toString()))
129136
}
137+
130138
// Set grid mode
131139
cy.login(user)
132-
cy.intercept('**/apps/files/api/v1/config/grid_view').as('setGridMode')
133140
cy.visit('/apps/files')
134-
cy.findByRole('button', { name: 'Switch to grid view' })
135-
.should('be.visible')
136-
.click()
137-
cy.wait('@setGridMode')
141+
enableGridMode()
142+
143+
// 768px width will limit the columns to 3
144+
cy.viewport(768, 800)
145+
// Calculate height to ensure that those 12 elements can not be rendered in one list (only 3 will fit the screen)
146+
calculateViewportHeight(3)
147+
.then((height) => { viewportHeight = height })
138148
})
139149
})
140150

141151
beforeEach(() => {
142-
// Adjust height to ensure that those 12 files can not be rendered in one list
143-
// 768px width will limit the columns to 3
144-
cy.viewport(768, 3 * 246 /* rows */ + 55 /* table header */ + 50 /* navigation header */ + 50 /* breadcrumbs */ + 46 /* file filters */)
152+
cy.viewport(768, viewportHeight)
145153
cy.login(user)
146154
})
147155

@@ -244,6 +252,35 @@ describe('files: Scrolling to selected file in file list (GRID MODE)', { testIso
244252

245253
/// Some helpers
246254

255+
/**
256+
* Calculate the needed viewport height to limit the visible rows of the file list.
257+
*
258+
* @param rows The number of rows that should be displayed at the same time
259+
* @returns The wrapped result
260+
*/
261+
function calculateViewportHeight(rows: number): Cypress.Chainable<number> {
262+
cy.visit('/apps/files')
263+
return cy.get('[data-cy-files-list]')
264+
.should('be.visible')
265+
.then((filesList) => {
266+
const windowHeight = Cypress.$('body').height()!
267+
// Size of other page elements
268+
const outerHeight = Math.ceil(windowHeight - filesList.height()!)
269+
// Size of before and filters
270+
const beforeHeight = Math.ceil(Cypress.$('.files-list__before').height()!)
271+
const filterHeight = Math.ceil(Cypress.$('.files-list__filters').height()!)
272+
// Size of the table header
273+
const tableHeaderHeight = Math.ceil(Cypress.$('[data-cy-files-list-thead]').height()!)
274+
// table row height
275+
const rowHeight = Math.ceil(Cypress.$('[data-cy-files-list-tbody] tr').height()!)
276+
277+
// sum it up
278+
const viewportHeight = outerHeight + beforeHeight + filterHeight + tableHeaderHeight + rows * rowHeight
279+
cy.log(`Calculated viewport height: ${viewportHeight} (${outerHeight} + ${beforeHeight} + ${filterHeight} + ${tableHeaderHeight} + ${rows} * ${rowHeight})`)
280+
return cy.wrap(viewportHeight)
281+
})
282+
}
283+
247284
function notBeOverlappedByTableHeader($el: JQuery<HTMLElement>) {
248285
return beOverlappedByTableHeader($el, false)
249286
}
@@ -262,19 +299,3 @@ function beOverlappedByTableHeader($el: JQuery<HTMLElement>, expected = true) {
262299
expect(overlap, 'Not overlapped by table header').to.be.false
263300
}
264301
}
265-
266-
function beFullyInViewport($el: JQuery<HTMLElement>, expected = true) {
267-
const { top, left, bottom, right } = $el.get(0)!.getBoundingClientRect()
268-
const { innerHeight, innerWidth } = window
269-
const fullyVisible = top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth
270-
271-
if (expected) {
272-
expect(fullyVisible, 'Fully within viewport').to.be.true
273-
} else {
274-
expect(fullyVisible, 'Not fully within viewport').to.be.false
275-
}
276-
}
277-
278-
function notBeFullyInViewport($el: JQuery<HTMLElement>) {
279-
return beFullyInViewport($el, false)
280-
}

0 commit comments

Comments
 (0)