aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2023-11-16 02:39:40 +0100
committerFerdinand Thiessen <opensource@fthiessen.de>2023-11-16 14:25:43 +0100
commit205801adc6911e0fe368f6cc3a10a559c6aa0ebf (patch)
treeb6b541c844b8fdeca7dab61ca1543d48a23cc7df
parente250a561701ce010188a3c3a84b522dc51aed878 (diff)
downloadnextcloud-server-205801adc6911e0fe368f6cc3a10a559c6aa0ebf.tar.gz
nextcloud-server-205801adc6911e0fe368f6cc3a10a559c6aa0ebf.zip
fix(files): Add cypress e2e tests
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
-rw-r--r--cypress/e2e/files/files.cy.ts (renamed from cypress/e2e/files.cy.ts)12
-rw-r--r--cypress/e2e/files/files_sorting.cy.ts262
-rw-r--r--cypress/support/commands.ts73
3 files changed, 336 insertions, 11 deletions
diff --git a/cypress/e2e/files.cy.ts b/cypress/e2e/files/files.cy.ts
index 490ddff2d0e..33261be417e 100644
--- a/cypress/e2e/files.cy.ts
+++ b/cypress/e2e/files/files.cy.ts
@@ -19,21 +19,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
-describe('Login with a new user and open the files app', function() {
- before(function() {
+describe('Files', { testIsolation: true }, () => {
+ beforeEach(() => {
cy.createRandomUser().then((user) => {
cy.login(user)
})
})
- after(function() {
- cy.logout()
- })
-
- it('See the default file welcome.txt in the files list', function() {
+ it('Login with a user and open the files app', () => {
cy.visit('/apps/files')
cy.get('[data-cy-files-list] [data-cy-files-list-row-name="welcome.txt"]').should('be.visible')
- // eslint-disable-next-line cypress/no-unnecessary-waiting -- Wait for all to finish loading
- cy.wait(500)
})
})
diff --git a/cypress/e2e/files/files_sorting.cy.ts b/cypress/e2e/files/files_sorting.cy.ts
new file mode 100644
index 00000000000..b0ce1b6d723
--- /dev/null
+++ b/cypress/e2e/files/files_sorting.cy.ts
@@ -0,0 +1,262 @@
+/**
+ * @copyright Copyright (c) 2022 John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @author John Molakvoæ <skjnldsv@protonmail.com>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+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
+ }
+ })
+ })
+
+ 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('1 tiny.txt')
+ break
+ case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('folder')
+ 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('z big.txt')
+ break
+ case 1: expect($row.attr('data-cy-files-list-row-name')).to.eq('a medium.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('folder')
+ 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/support/commands.ts b/cypress/support/commands.ts
index b2ec7f1e745..477a366a421 100644
--- a/cypress/support/commands.ts
+++ b/cypress/support/commands.ts
@@ -49,7 +49,18 @@ declare global {
* Upload a raw content to a given user storage.
* **Warning**: Using this function will reset the previous session
*/
- uploadContent(user: User, content: Blob, mimeType: string, target: string): Cypress.Chainable<void>,
+ uploadContent(user: User, content: Blob, mimeType: string, target: string, mtime?: number): Cypress.Chainable<void>,
+
+ /**
+ * Create a new directory
+ * **Warning**: Using this function will reset the previous session
+ */
+ mkdir(user: User, target: string): Cypress.Chainable<void>,
+
+ /**
+ * Set a file as favorite (or remove from favorite)
+ */
+ setFileAsFavorite(user: User, target: string, favorite?: boolean): Cypress.Chainable<void>,
/**
* Reset the admin theming entirely.
@@ -121,6 +132,63 @@ Cypress.Commands.add('uploadFile', (user, fixture = 'image.jpg', mimeType = 'ima
})
})
+Cypress.Commands.add('setFileAsFavorite', (user: User, target: string, favorite = true) => {
+ // eslint-disable-next-line cypress/unsafe-to-chain-command
+ cy.clearAllCookies()
+ .then(async () => {
+ try {
+ const rootPath = `${Cypress.env('baseUrl')}/remote.php/dav/files/${encodeURIComponent(user.userId)}`
+ const filePath = target.split('/').map(encodeURIComponent).join('/')
+ const response = await axios({
+ url: `${rootPath}${filePath}`,
+ method: 'PROPPATCH',
+ auth: {
+ username: user.userId,
+ password: user.password,
+ },
+ headers: {
+ 'Content-Type': 'application/xml',
+ },
+ data: `<?xml version="1.0"?>
+ <d:propertyupdate xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
+ <d:set>
+ <d:prop>
+ <oc:favorite>${favorite ? 1 : 0}</oc:favorite>
+ </d:prop>
+ </d:set>
+ </d:propertyupdate>`
+ })
+ cy.log(`Created directory ${target}`, response)
+ } catch (error) {
+ cy.log('error', error)
+ throw new Error('Unable to process fixture')
+ }
+ })
+})
+
+Cypress.Commands.add('mkdir', (user: User, target: string) => {
+ // eslint-disable-next-line cypress/unsafe-to-chain-command
+ cy.clearCookies()
+ .then(async () => {
+ try {
+ const rootPath = `${Cypress.env('baseUrl')}/remote.php/dav/files/${encodeURIComponent(user.userId)}`
+ const filePath = target.split('/').map(encodeURIComponent).join('/')
+ const response = await axios({
+ url: `${rootPath}${filePath}`,
+ method: 'MKCOL',
+ auth: {
+ username: user.userId,
+ password: user.password,
+ },
+ })
+ cy.log(`Created directory ${target}`, response)
+ } catch (error) {
+ cy.log('error', error)
+ throw new Error('Unable to process fixture')
+ }
+ })
+})
+
/**
* cy.uploadedContent - uploads a raw content
* TODO: standardise in @nextcloud/cypress
@@ -130,7 +198,7 @@ Cypress.Commands.add('uploadFile', (user, fixture = 'image.jpg', mimeType = 'ima
* @param {string} mimeType e.g. image/png
* @param {string} target the target of the file relative to the user root
*/
-Cypress.Commands.add('uploadContent', (user, blob, mimeType, target) => {
+Cypress.Commands.add('uploadContent', (user, blob, mimeType, target, mtime = undefined) => {
// eslint-disable-next-line cypress/unsafe-to-chain-command
cy.clearCookies()
.then(async () => {
@@ -147,6 +215,7 @@ Cypress.Commands.add('uploadContent', (user, blob, mimeType, target) => {
data: file,
headers: {
'Content-Type': mimeType,
+ 'X-OC-MTime': mtime ? `${mtime}` : undefined,
},
auth: {
username: user.userId,