]> source.dussan.org Git - nextcloud-server.git/commitdiff
chore(files): add selection cypress tests
authorskjnldsv <skjnldsv@protonmail.com>
Thu, 7 Nov 2024 18:00:35 +0000 (19:00 +0100)
committerskjnldsv <skjnldsv@protonmail.com>
Thu, 7 Nov 2024 18:01:59 +0000 (19:01 +0100)
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
cypress/e2e/files/FilesUtils.ts
cypress/e2e/files/files-copy-move.cy.ts [new file with mode: 0644]
cypress/e2e/files/files-selection.cy.ts [new file with mode: 0644]
cypress/e2e/files/files-sorting.cy.ts [new file with mode: 0644]
cypress/e2e/files/files_copy-move.cy.ts [deleted file]
cypress/e2e/files/files_sorting.cy.ts [deleted file]

index 182972ee44c138e0eb941414c63f689297459f53..f435272b9a2cefdd493807fd94c3aeb2cf62cee6 100644 (file)
@@ -33,13 +33,22 @@ export const triggerInlineActionForFile = (filename: string, actionId: string) =
 }
 
 export const selectAllFiles = () => {
-       cy.get('[data-cy-files-list-selection-checkbox]').findByRole('checkbox').click({ force: true })
+       cy.get('[data-cy-files-list-selection-checkbox]')
+               .findByRole('checkbox', { checked: false })
+               .click({ force: true })
+}
+export const deselectAllFiles = () => {
+       cy.get('[data-cy-files-list-selection-checkbox]')
+               .findByRole('checkbox', { checked: true })
+               .click({ force: true })
 }
-export const selectRowForFile = (filename: string) => {
+
+export const selectRowForFile = (filename: string, options: Partial<Cypress.ClickOptions> = {}) => {
        getRowForFile(filename)
                .find('[data-cy-files-list-row-checkbox]')
                .findByRole('checkbox')
-               .click({ force: true })
+               // don't use click to avoid triggering side effects events
+               .trigger('change', { ...options, force: true })
                .should('be.checked')
        cy.get('[data-cy-files-list-selection-checkbox]').findByRole('checkbox').should('satisfy', (elements) => {
                return elements.length === 1 && (elements[0].checked === true || elements[0].indeterminate === true)
diff --git a/cypress/e2e/files/files-copy-move.cy.ts b/cypress/e2e/files/files-copy-move.cy.ts
new file mode 100644 (file)
index 0000000..086248e
--- /dev/null
@@ -0,0 +1,177 @@
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import { getRowForFile, moveFile, copyFile, navigateToFolder } from './FilesUtils.ts'
+
+describe('Files: Move or copy files', { testIsolation: true }, () => {
+       let currentUser
+       beforeEach(() => {
+               cy.createRandomUser().then((user) => {
+                       currentUser = user
+                       cy.login(user)
+               })
+       })
+       afterEach(() => {
+               // nice to have cleanup
+               cy.deleteUser(currentUser)
+       })
+
+
+       it('Can copy a file to new folder', () => {
+               // Prepare initial state
+               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
+                       .mkdir(currentUser, '/new-folder')
+               cy.login(currentUser)
+               cy.visit('/apps/files')
+
+               copyFile('original.txt', 'new-folder')
+
+               navigateToFolder('new-folder')
+
+               cy.url().should('contain', 'dir=/new-folder')
+               getRowForFile('original.txt').should('be.visible')
+               getRowForFile('new-folder').should('not.exist')
+       })
+
+       it('Can move a file to new folder', () => {
+               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
+                       .mkdir(currentUser, '/new-folder')
+               cy.login(currentUser)
+               cy.visit('/apps/files')
+
+               moveFile('original.txt', 'new-folder')
+
+               // wait until visible again
+               getRowForFile('new-folder').should('be.visible')
+
+               // original should be moved -> not exist anymore
+               getRowForFile('original.txt').should('not.exist')
+               navigateToFolder('new-folder')
+
+               cy.url().should('contain', 'dir=/new-folder')
+               getRowForFile('original.txt').should('be.visible')
+               getRowForFile('new-folder').should('not.exist')
+       })
+
+       /**
+        * Test for https://github.com/nextcloud/server/issues/41768
+        */
+       it('Can move a file to folder with similar name', () => {
+               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original')
+                       .mkdir(currentUser, '/original folder')
+               cy.login(currentUser)
+               cy.visit('/apps/files')
+
+               moveFile('original', 'original folder')
+
+               // wait until visible again
+               getRowForFile('original folder').should('be.visible')
+
+               // original should be moved -> not exist anymore
+               getRowForFile('original').should('not.exist')
+               navigateToFolder('original folder')
+
+               cy.url().should('contain', 'dir=/original%20folder')
+               getRowForFile('original').should('be.visible')
+               getRowForFile('original folder').should('not.exist')
+       })
+
+       it('Can move a file to its parent folder', () => {
+               cy.mkdir(currentUser, '/new-folder')
+               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/new-folder/original.txt')
+               cy.login(currentUser)
+               cy.visit('/apps/files')
+
+               navigateToFolder('new-folder')
+               cy.url().should('contain', 'dir=/new-folder')
+
+               moveFile('original.txt', '/')
+
+               // wait until visible again
+               cy.get('main').contains('No files in here').should('be.visible')
+
+               // original should be moved -> not exist anymore
+               getRowForFile('original.txt').should('not.exist')
+
+               cy.visit('/apps/files')
+               getRowForFile('new-folder').should('be.visible')
+               getRowForFile('original.txt').should('be.visible')
+       })
+
+       it('Can copy a file to same folder', () => {
+               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
+               cy.login(currentUser)
+               cy.visit('/apps/files')
+
+               copyFile('original.txt', '.')
+
+               getRowForFile('original.txt').should('be.visible')
+               getRowForFile('original (copy).txt').should('be.visible')
+       })
+
+       it('Can copy a file multiple times to same folder', () => {
+               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
+               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original (copy).txt')
+               cy.login(currentUser)
+               cy.visit('/apps/files')
+
+               copyFile('original.txt', '.')
+
+               getRowForFile('original.txt').should('be.visible')
+               getRowForFile('original (copy 2).txt').should('be.visible')
+       })
+
+       /**
+        * Test that a copied folder with a dot will be renamed correctly ('foo.bar' -> 'foo.bar (copy)')
+        * Test for: https://github.com/nextcloud/server/issues/43843
+        */
+       it('Can copy a folder to same folder', () => {
+               cy.mkdir(currentUser, '/foo.bar')
+               cy.login(currentUser)
+               cy.visit('/apps/files')
+
+               copyFile('foo.bar', '.')
+
+               getRowForFile('foo.bar').should('be.visible')
+               getRowForFile('foo.bar (copy)').should('be.visible')
+       })
+
+       /** Test for https://github.com/nextcloud/server/issues/43329 */
+       context('escaping file and folder names', () => {
+               it('Can handle files with special characters', () => {
+                       cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
+                               .mkdir(currentUser, '/can\'t say')
+                       cy.login(currentUser)
+                       cy.visit('/apps/files')
+
+                       copyFile('original.txt', 'can\'t say')
+
+                       navigateToFolder('can\'t say')
+
+                       cy.url().should('contain', 'dir=/can%27t%20say')
+                       getRowForFile('original.txt').should('be.visible')
+                       getRowForFile('can\'t say').should('not.exist')
+               })
+
+               /**
+                * If escape is set to false (required for test above) then "<a>foo" would result in "<a>foo</a>" if sanitizing is not disabled
+                * We should disable it as vue already escapes the text when using v-text
+                */
+               it('does not incorrectly sanitize file names', () => {
+                       cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
+                               .mkdir(currentUser, '/<a href="#">foo')
+                       cy.login(currentUser)
+                       cy.visit('/apps/files')
+
+                       copyFile('original.txt', '<a href="#">foo')
+
+                       navigateToFolder('<a href="#">foo')
+
+                       cy.url().should('contain', 'dir=/%3Ca%20href%3D%22%23%22%3Efoo')
+                       getRowForFile('original.txt').should('be.visible')
+                       getRowForFile('<a href="#">foo').should('not.exist')
+               })
+       })
+})
diff --git a/cypress/e2e/files/files-selection.cy.ts b/cypress/e2e/files/files-selection.cy.ts
new file mode 100644 (file)
index 0000000..04991b7
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import type { User } from '@nextcloud/cypress'
+import { deselectAllFiles, selectAllFiles, selectRowForFile } from './FilesUtils'
+
+const files = {
+       'image.jpg': 'image/jpeg',
+       'document.pdf': 'application/pdf',
+       'archive.zip': 'application/zip',
+       'audio.mp3': 'audio/mpeg',
+       'video.mp4': 'video/mp4',
+       'readme.md': 'text/markdown',
+       'welcome.txt': 'text/plain',
+}
+const filesCount = Object.keys(files).length
+
+describe('files: Select all files', { testIsolation: true }, () => {
+       let user: User
+
+       before(() => {
+               cy.createRandomUser().then(($user) => {
+                       user = $user
+                       Object.keys(files).forEach((file) => {
+                               cy.uploadContent(user, new Blob(), files[file], '/' + file)
+                       })
+               })
+       })
+
+       beforeEach(() => {
+               cy.login(user)
+               cy.visit('/apps/files')
+       })
+
+       it('Can select and unselect all files', () => {
+               cy.get('[data-cy-files-list-row-fileid]').should('have.length', filesCount)
+               cy.get('[data-cy-files-list-row-checkbox]').should('have.length', filesCount)
+
+               selectAllFiles()
+
+               cy.get('.files-list__selected').should('have.text', '7 selected')
+               cy.get('[data-cy-files-list-row-checkbox]').findByRole('checkbox').should('be.checked')
+
+               deselectAllFiles()
+
+               cy.get('.files-list__selected').should('not.exist')
+               cy.get('[data-cy-files-list-row-checkbox]').findByRole('checkbox').should('not.be.checked')
+       })
+
+       it('Can select some files randomly', () => {
+               const randomFiles = Object.keys(files).reduce((acc, file) => {
+                       if (Math.random() > 0.1) {
+                               acc.push(file)
+                       }
+                       return acc
+               }, [] as string[])
+
+               randomFiles.forEach(name => selectRowForFile(name))
+
+               cy.get('.files-list__selected').should('have.text', `${randomFiles.length} selected`)
+               cy.get('[data-cy-files-list-row-checkbox] input[type="checkbox"]:checked').should('have.length', randomFiles.length)
+       })
+
+       it('Can select range of files with shift key', () => {
+               cy.get('[data-cy-files-list-row-checkbox]').should('have.length', filesCount)
+               selectRowForFile('audio.mp3')
+               cy.window().trigger('keydown', { shiftKey: true })
+               selectRowForFile('readme.md', { shiftKey: true })
+               cy.window().trigger('keyup', { shiftKey: false })
+
+               cy.get('.files-list__selected').should('have.text', '4 selected')
+               cy.get('[data-cy-files-list-row-checkbox] input[type="checkbox"]:checked').should('have.length', 4)
+
+       })
+})
diff --git a/cypress/e2e/files/files-sorting.cy.ts b/cypress/e2e/files/files-sorting.cy.ts
new file mode 100644 (file)
index 0000000..250c5f1
--- /dev/null
@@ -0,0 +1,270 @@
+/**
+ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+describe('Files: Sorting the file list', { testIsolation: true }, () => {
+       let currentUser
+       beforeEach(() => {
+               cy.createRandomUser().then((user) => {
+                       currentUser = user
+                       cy.login(user)
+               })
+       })
+
+       it('Files are sorted by name ascending by default', () => {
+               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/1 first.txt')
+                       .uploadContent(currentUser, new Blob(), 'text/plain', '/z last.txt')
+                       .uploadContent(currentUser, new Blob(), 'text/plain', '/A.txt')
+                       .uploadContent(currentUser, new Blob(), 'text/plain', '/Ä.txt')
+                       .mkdir(currentUser, '/m')
+                       .mkdir(currentUser, '/4')
+               cy.login(currentUser)
+               cy.visit('/apps/files')
+
+               cy.get('[data-cy-files-list-row]').each(($row, index) => {
+                       switch (index) {
+                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('4')
+                               break
+                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('m')
+                               break
+                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('1 first.txt')
+                               break
+                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('A.txt')
+                               break
+                       case 4: expect($row.attr('data-cy-files-list-row-name')).to.eq('Ä.txt')
+                               break
+                       case 5: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
+                               break
+                       case 6: expect($row.attr('data-cy-files-list-row-name')).to.eq('z last.txt')
+                               break
+                       }
+               })
+       })
+
+       /**
+        * Regression test of https://github.com/nextcloud/server/issues/45829
+        */
+       it('Filesnames with numbers are sorted by name ascending by default', () => {
+               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/name.txt')
+                       .uploadContent(currentUser, new Blob(), 'text/plain', '/name_03.txt')
+                       .uploadContent(currentUser, new Blob(), 'text/plain', '/name_02.txt')
+                       .uploadContent(currentUser, new Blob(), 'text/plain', '/name_01.txt')
+               cy.login(currentUser)
+               cy.visit('/apps/files')
+
+               cy.get('[data-cy-files-list-row]').each(($row, index) => {
+                       switch (index) {
+                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('name.txt')
+                               break
+                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('name_01.txt')
+                               break
+                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('name_02.txt')
+                               break
+                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('name_03.txt')
+                               break
+                       }
+               })
+       })
+
+       it('Can sort by size', () => {
+               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/1 tiny.txt')
+                       .uploadContent(currentUser, new Blob(['a'.repeat(1024)]), 'text/plain', '/z big.txt')
+                       .uploadContent(currentUser, new Blob(['a'.repeat(512)]), 'text/plain', '/a medium.txt')
+                       .mkdir(currentUser, '/folder')
+               cy.login(currentUser)
+               cy.visit('/apps/files')
+
+               // click sort button
+               cy.get('th').contains('button', 'Size').click()
+               // sorting is set
+               cy.contains('th', 'Size').should('have.attr', 'aria-sort', 'ascending')
+               // Files are sorted
+               cy.get('[data-cy-files-list-row]').each(($row, index) => {
+                       switch (index) {
+                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('folder')
+                               break
+                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('1 tiny.txt')
+                               break
+                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
+                               break
+                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('a medium.txt')
+                               break
+                       case 4: expect($row.attr('data-cy-files-list-row-name')).to.eq('z big.txt')
+                               break
+                       }
+               })
+
+               // click sort button
+               cy.get('th').contains('button', 'Size').click()
+               // sorting is set
+               cy.contains('th', 'Size').should('have.attr', 'aria-sort', 'descending')
+               // Files are sorted
+               cy.get('[data-cy-files-list-row]').each(($row, index) => {
+                       switch (index) {
+                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('folder')
+                               break
+                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('z big.txt')
+                               break
+                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('a medium.txt')
+                               break
+                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
+                               break
+                       case 4: expect($row.attr('data-cy-files-list-row-name')).to.eq('1 tiny.txt')
+                               break
+                       }
+               })
+       })
+
+       it('Can sort by mtime', () => {
+               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/1.txt', Date.now() / 1000 - 86400 - 1000)
+                       .uploadContent(currentUser, new Blob(['a'.repeat(1024)]), 'text/plain', '/z.txt', Date.now() / 1000 - 86400)
+                       .uploadContent(currentUser, new Blob(['a'.repeat(512)]), 'text/plain', '/a.txt', Date.now() / 1000 - 86400 - 500)
+               cy.login(currentUser)
+               cy.visit('/apps/files')
+
+               // click sort button
+               cy.get('th').contains('button', 'Modified').click()
+               // sorting is set
+               cy.contains('th', 'Modified').should('have.attr', 'aria-sort', 'ascending')
+               // Files are sorted
+               cy.get('[data-cy-files-list-row]').each(($row, index) => {
+                       switch (index) {
+                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt') // uploaded right now
+                               break
+                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt') // fake time of yesterday
+                               break
+                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt') // fake time of yesterday and few minutes
+                               break
+                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt') // fake time of yesterday and ~15 minutes ago
+                               break
+                       }
+               })
+
+               // reverse order
+               cy.get('th').contains('button', 'Modified').click()
+               cy.contains('th', 'Modified').should('have.attr', 'aria-sort', 'descending')
+               cy.get('[data-cy-files-list-row]').each(($row, index) => {
+                       switch (index) {
+                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt') // uploaded right now
+                               break
+                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt') // fake time of yesterday
+                               break
+                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt') // fake time of yesterday and few minutes
+                               break
+                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt') // fake time of yesterday and ~15 minutes ago
+                               break
+                       }
+               })
+       })
+
+       it('Favorites are sorted first', () => {
+               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/1.txt', Date.now() / 1000 - 86400 - 1000)
+                       .uploadContent(currentUser, new Blob(['a'.repeat(1024)]), 'text/plain', '/z.txt', Date.now() / 1000 - 86400)
+                       .uploadContent(currentUser, new Blob(['a'.repeat(512)]), 'text/plain', '/a.txt', Date.now() / 1000 - 86400 - 500)
+                       .setFileAsFavorite(currentUser, '/a.txt')
+               cy.login(currentUser)
+               cy.visit('/apps/files')
+
+               cy.log('By name - ascending')
+               cy.get('th').contains('button', 'Name').click()
+               cy.contains('th', 'Name').should('have.attr', 'aria-sort', 'ascending')
+
+               cy.get('[data-cy-files-list-row]').each(($row, index) => {
+                       switch (index) {
+                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt')
+                               break
+                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt')
+                               break
+                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
+                               break
+                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt')
+                               break
+                       }
+               })
+
+               cy.log('By name - descending')
+               cy.get('th').contains('button', 'Name').click()
+               cy.contains('th', 'Name').should('have.attr', 'aria-sort', 'descending')
+
+               cy.get('[data-cy-files-list-row]').each(($row, index) => {
+                       switch (index) {
+                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt')
+                               break
+                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt')
+                               break
+                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
+                               break
+                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt')
+                               break
+                       }
+               })
+
+               cy.log('By size - ascending')
+               cy.get('th').contains('button', 'Size').click()
+               cy.contains('th', 'Size').should('have.attr', 'aria-sort', 'ascending')
+
+               cy.get('[data-cy-files-list-row]').each(($row, index) => {
+                       switch (index) {
+                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt')
+                               break
+                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt')
+                               break
+                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
+                               break
+                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt')
+                               break
+                       }
+               })
+
+               cy.log('By size - descending')
+               cy.get('th').contains('button', 'Size').click()
+               cy.contains('th', 'Size').should('have.attr', 'aria-sort', 'descending')
+
+               cy.get('[data-cy-files-list-row]').each(($row, index) => {
+                       switch (index) {
+                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt')
+                               break
+                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt')
+                               break
+                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
+                               break
+                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt')
+                               break
+                       }
+               })
+
+               cy.log('By mtime - ascending')
+               cy.get('th').contains('button', 'Modified').click()
+               cy.contains('th', 'Modified').should('have.attr', 'aria-sort', 'ascending')
+
+               cy.get('[data-cy-files-list-row]').each(($row, index) => {
+                       switch (index) {
+                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt')
+                               break
+                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
+                               break
+                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt')
+                               break
+                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt')
+                               break
+                       }
+               })
+
+               cy.log('By mtime - descending')
+               cy.get('th').contains('button', 'Modified').click()
+               cy.contains('th', 'Modified').should('have.attr', 'aria-sort', 'descending')
+
+               cy.get('[data-cy-files-list-row]').each(($row, index) => {
+                       switch (index) {
+                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt')
+                               break
+                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt')
+                               break
+                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt')
+                               break
+                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
+                               break
+                       }
+               })
+       })
+})
diff --git a/cypress/e2e/files/files_copy-move.cy.ts b/cypress/e2e/files/files_copy-move.cy.ts
deleted file mode 100644 (file)
index 086248e..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/**
- * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-import { getRowForFile, moveFile, copyFile, navigateToFolder } from './FilesUtils.ts'
-
-describe('Files: Move or copy files', { testIsolation: true }, () => {
-       let currentUser
-       beforeEach(() => {
-               cy.createRandomUser().then((user) => {
-                       currentUser = user
-                       cy.login(user)
-               })
-       })
-       afterEach(() => {
-               // nice to have cleanup
-               cy.deleteUser(currentUser)
-       })
-
-
-       it('Can copy a file to new folder', () => {
-               // Prepare initial state
-               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
-                       .mkdir(currentUser, '/new-folder')
-               cy.login(currentUser)
-               cy.visit('/apps/files')
-
-               copyFile('original.txt', 'new-folder')
-
-               navigateToFolder('new-folder')
-
-               cy.url().should('contain', 'dir=/new-folder')
-               getRowForFile('original.txt').should('be.visible')
-               getRowForFile('new-folder').should('not.exist')
-       })
-
-       it('Can move a file to new folder', () => {
-               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
-                       .mkdir(currentUser, '/new-folder')
-               cy.login(currentUser)
-               cy.visit('/apps/files')
-
-               moveFile('original.txt', 'new-folder')
-
-               // wait until visible again
-               getRowForFile('new-folder').should('be.visible')
-
-               // original should be moved -> not exist anymore
-               getRowForFile('original.txt').should('not.exist')
-               navigateToFolder('new-folder')
-
-               cy.url().should('contain', 'dir=/new-folder')
-               getRowForFile('original.txt').should('be.visible')
-               getRowForFile('new-folder').should('not.exist')
-       })
-
-       /**
-        * Test for https://github.com/nextcloud/server/issues/41768
-        */
-       it('Can move a file to folder with similar name', () => {
-               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original')
-                       .mkdir(currentUser, '/original folder')
-               cy.login(currentUser)
-               cy.visit('/apps/files')
-
-               moveFile('original', 'original folder')
-
-               // wait until visible again
-               getRowForFile('original folder').should('be.visible')
-
-               // original should be moved -> not exist anymore
-               getRowForFile('original').should('not.exist')
-               navigateToFolder('original folder')
-
-               cy.url().should('contain', 'dir=/original%20folder')
-               getRowForFile('original').should('be.visible')
-               getRowForFile('original folder').should('not.exist')
-       })
-
-       it('Can move a file to its parent folder', () => {
-               cy.mkdir(currentUser, '/new-folder')
-               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/new-folder/original.txt')
-               cy.login(currentUser)
-               cy.visit('/apps/files')
-
-               navigateToFolder('new-folder')
-               cy.url().should('contain', 'dir=/new-folder')
-
-               moveFile('original.txt', '/')
-
-               // wait until visible again
-               cy.get('main').contains('No files in here').should('be.visible')
-
-               // original should be moved -> not exist anymore
-               getRowForFile('original.txt').should('not.exist')
-
-               cy.visit('/apps/files')
-               getRowForFile('new-folder').should('be.visible')
-               getRowForFile('original.txt').should('be.visible')
-       })
-
-       it('Can copy a file to same folder', () => {
-               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
-               cy.login(currentUser)
-               cy.visit('/apps/files')
-
-               copyFile('original.txt', '.')
-
-               getRowForFile('original.txt').should('be.visible')
-               getRowForFile('original (copy).txt').should('be.visible')
-       })
-
-       it('Can copy a file multiple times to same folder', () => {
-               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
-               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original (copy).txt')
-               cy.login(currentUser)
-               cy.visit('/apps/files')
-
-               copyFile('original.txt', '.')
-
-               getRowForFile('original.txt').should('be.visible')
-               getRowForFile('original (copy 2).txt').should('be.visible')
-       })
-
-       /**
-        * Test that a copied folder with a dot will be renamed correctly ('foo.bar' -> 'foo.bar (copy)')
-        * Test for: https://github.com/nextcloud/server/issues/43843
-        */
-       it('Can copy a folder to same folder', () => {
-               cy.mkdir(currentUser, '/foo.bar')
-               cy.login(currentUser)
-               cy.visit('/apps/files')
-
-               copyFile('foo.bar', '.')
-
-               getRowForFile('foo.bar').should('be.visible')
-               getRowForFile('foo.bar (copy)').should('be.visible')
-       })
-
-       /** Test for https://github.com/nextcloud/server/issues/43329 */
-       context('escaping file and folder names', () => {
-               it('Can handle files with special characters', () => {
-                       cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
-                               .mkdir(currentUser, '/can\'t say')
-                       cy.login(currentUser)
-                       cy.visit('/apps/files')
-
-                       copyFile('original.txt', 'can\'t say')
-
-                       navigateToFolder('can\'t say')
-
-                       cy.url().should('contain', 'dir=/can%27t%20say')
-                       getRowForFile('original.txt').should('be.visible')
-                       getRowForFile('can\'t say').should('not.exist')
-               })
-
-               /**
-                * If escape is set to false (required for test above) then "<a>foo" would result in "<a>foo</a>" if sanitizing is not disabled
-                * We should disable it as vue already escapes the text when using v-text
-                */
-               it('does not incorrectly sanitize file names', () => {
-                       cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
-                               .mkdir(currentUser, '/<a href="#">foo')
-                       cy.login(currentUser)
-                       cy.visit('/apps/files')
-
-                       copyFile('original.txt', '<a href="#">foo')
-
-                       navigateToFolder('<a href="#">foo')
-
-                       cy.url().should('contain', 'dir=/%3Ca%20href%3D%22%23%22%3Efoo')
-                       getRowForFile('original.txt').should('be.visible')
-                       getRowForFile('<a href="#">foo').should('not.exist')
-               })
-       })
-})
diff --git a/cypress/e2e/files/files_sorting.cy.ts b/cypress/e2e/files/files_sorting.cy.ts
deleted file mode 100644 (file)
index 250c5f1..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/**
- * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-describe('Files: Sorting the file list', { testIsolation: true }, () => {
-       let currentUser
-       beforeEach(() => {
-               cy.createRandomUser().then((user) => {
-                       currentUser = user
-                       cy.login(user)
-               })
-       })
-
-       it('Files are sorted by name ascending by default', () => {
-               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/1 first.txt')
-                       .uploadContent(currentUser, new Blob(), 'text/plain', '/z last.txt')
-                       .uploadContent(currentUser, new Blob(), 'text/plain', '/A.txt')
-                       .uploadContent(currentUser, new Blob(), 'text/plain', '/Ä.txt')
-                       .mkdir(currentUser, '/m')
-                       .mkdir(currentUser, '/4')
-               cy.login(currentUser)
-               cy.visit('/apps/files')
-
-               cy.get('[data-cy-files-list-row]').each(($row, index) => {
-                       switch (index) {
-                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('4')
-                               break
-                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('m')
-                               break
-                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('1 first.txt')
-                               break
-                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('A.txt')
-                               break
-                       case 4: expect($row.attr('data-cy-files-list-row-name')).to.eq('Ä.txt')
-                               break
-                       case 5: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
-                               break
-                       case 6: expect($row.attr('data-cy-files-list-row-name')).to.eq('z last.txt')
-                               break
-                       }
-               })
-       })
-
-       /**
-        * Regression test of https://github.com/nextcloud/server/issues/45829
-        */
-       it('Filesnames with numbers are sorted by name ascending by default', () => {
-               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/name.txt')
-                       .uploadContent(currentUser, new Blob(), 'text/plain', '/name_03.txt')
-                       .uploadContent(currentUser, new Blob(), 'text/plain', '/name_02.txt')
-                       .uploadContent(currentUser, new Blob(), 'text/plain', '/name_01.txt')
-               cy.login(currentUser)
-               cy.visit('/apps/files')
-
-               cy.get('[data-cy-files-list-row]').each(($row, index) => {
-                       switch (index) {
-                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('name.txt')
-                               break
-                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('name_01.txt')
-                               break
-                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('name_02.txt')
-                               break
-                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('name_03.txt')
-                               break
-                       }
-               })
-       })
-
-       it('Can sort by size', () => {
-               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/1 tiny.txt')
-                       .uploadContent(currentUser, new Blob(['a'.repeat(1024)]), 'text/plain', '/z big.txt')
-                       .uploadContent(currentUser, new Blob(['a'.repeat(512)]), 'text/plain', '/a medium.txt')
-                       .mkdir(currentUser, '/folder')
-               cy.login(currentUser)
-               cy.visit('/apps/files')
-
-               // click sort button
-               cy.get('th').contains('button', 'Size').click()
-               // sorting is set
-               cy.contains('th', 'Size').should('have.attr', 'aria-sort', 'ascending')
-               // Files are sorted
-               cy.get('[data-cy-files-list-row]').each(($row, index) => {
-                       switch (index) {
-                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('folder')
-                               break
-                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('1 tiny.txt')
-                               break
-                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
-                               break
-                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('a medium.txt')
-                               break
-                       case 4: expect($row.attr('data-cy-files-list-row-name')).to.eq('z big.txt')
-                               break
-                       }
-               })
-
-               // click sort button
-               cy.get('th').contains('button', 'Size').click()
-               // sorting is set
-               cy.contains('th', 'Size').should('have.attr', 'aria-sort', 'descending')
-               // Files are sorted
-               cy.get('[data-cy-files-list-row]').each(($row, index) => {
-                       switch (index) {
-                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('folder')
-                               break
-                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('z big.txt')
-                               break
-                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('a medium.txt')
-                               break
-                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
-                               break
-                       case 4: expect($row.attr('data-cy-files-list-row-name')).to.eq('1 tiny.txt')
-                               break
-                       }
-               })
-       })
-
-       it('Can sort by mtime', () => {
-               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/1.txt', Date.now() / 1000 - 86400 - 1000)
-                       .uploadContent(currentUser, new Blob(['a'.repeat(1024)]), 'text/plain', '/z.txt', Date.now() / 1000 - 86400)
-                       .uploadContent(currentUser, new Blob(['a'.repeat(512)]), 'text/plain', '/a.txt', Date.now() / 1000 - 86400 - 500)
-               cy.login(currentUser)
-               cy.visit('/apps/files')
-
-               // click sort button
-               cy.get('th').contains('button', 'Modified').click()
-               // sorting is set
-               cy.contains('th', 'Modified').should('have.attr', 'aria-sort', 'ascending')
-               // Files are sorted
-               cy.get('[data-cy-files-list-row]').each(($row, index) => {
-                       switch (index) {
-                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt') // uploaded right now
-                               break
-                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt') // fake time of yesterday
-                               break
-                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt') // fake time of yesterday and few minutes
-                               break
-                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt') // fake time of yesterday and ~15 minutes ago
-                               break
-                       }
-               })
-
-               // reverse order
-               cy.get('th').contains('button', 'Modified').click()
-               cy.contains('th', 'Modified').should('have.attr', 'aria-sort', 'descending')
-               cy.get('[data-cy-files-list-row]').each(($row, index) => {
-                       switch (index) {
-                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt') // uploaded right now
-                               break
-                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt') // fake time of yesterday
-                               break
-                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt') // fake time of yesterday and few minutes
-                               break
-                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt') // fake time of yesterday and ~15 minutes ago
-                               break
-                       }
-               })
-       })
-
-       it('Favorites are sorted first', () => {
-               cy.uploadContent(currentUser, new Blob(), 'text/plain', '/1.txt', Date.now() / 1000 - 86400 - 1000)
-                       .uploadContent(currentUser, new Blob(['a'.repeat(1024)]), 'text/plain', '/z.txt', Date.now() / 1000 - 86400)
-                       .uploadContent(currentUser, new Blob(['a'.repeat(512)]), 'text/plain', '/a.txt', Date.now() / 1000 - 86400 - 500)
-                       .setFileAsFavorite(currentUser, '/a.txt')
-               cy.login(currentUser)
-               cy.visit('/apps/files')
-
-               cy.log('By name - ascending')
-               cy.get('th').contains('button', 'Name').click()
-               cy.contains('th', 'Name').should('have.attr', 'aria-sort', 'ascending')
-
-               cy.get('[data-cy-files-list-row]').each(($row, index) => {
-                       switch (index) {
-                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt')
-                               break
-                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt')
-                               break
-                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
-                               break
-                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt')
-                               break
-                       }
-               })
-
-               cy.log('By name - descending')
-               cy.get('th').contains('button', 'Name').click()
-               cy.contains('th', 'Name').should('have.attr', 'aria-sort', 'descending')
-
-               cy.get('[data-cy-files-list-row]').each(($row, index) => {
-                       switch (index) {
-                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt')
-                               break
-                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt')
-                               break
-                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
-                               break
-                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt')
-                               break
-                       }
-               })
-
-               cy.log('By size - ascending')
-               cy.get('th').contains('button', 'Size').click()
-               cy.contains('th', 'Size').should('have.attr', 'aria-sort', 'ascending')
-
-               cy.get('[data-cy-files-list-row]').each(($row, index) => {
-                       switch (index) {
-                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt')
-                               break
-                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt')
-                               break
-                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
-                               break
-                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt')
-                               break
-                       }
-               })
-
-               cy.log('By size - descending')
-               cy.get('th').contains('button', 'Size').click()
-               cy.contains('th', 'Size').should('have.attr', 'aria-sort', 'descending')
-
-               cy.get('[data-cy-files-list-row]').each(($row, index) => {
-                       switch (index) {
-                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt')
-                               break
-                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt')
-                               break
-                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
-                               break
-                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt')
-                               break
-                       }
-               })
-
-               cy.log('By mtime - ascending')
-               cy.get('th').contains('button', 'Modified').click()
-               cy.contains('th', 'Modified').should('have.attr', 'aria-sort', 'ascending')
-
-               cy.get('[data-cy-files-list-row]').each(($row, index) => {
-                       switch (index) {
-                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt')
-                               break
-                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
-                               break
-                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt')
-                               break
-                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt')
-                               break
-                       }
-               })
-
-               cy.log('By mtime - descending')
-               cy.get('th').contains('button', 'Modified').click()
-               cy.contains('th', 'Modified').should('have.attr', 'aria-sort', 'descending')
-
-               cy.get('[data-cy-files-list-row]').each(($row, index) => {
-                       switch (index) {
-                       case 0: expect($row.attr('data-cy-files-list-row-name')).to.eq('a.txt')
-                               break
-                       case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('1.txt')
-                               break
-                       case 2: expect($row.attr('data-cy-files-list-row-name')).to.eq('z.txt')
-                               break
-                       case 3: expect($row.attr('data-cy-files-list-row-name')).to.eq('welcome.txt')
-                               break
-                       }
-               })
-       })
-})