diff options
author | Ferdinand Thiessen <opensource@fthiessen.de> | 2023-11-16 02:39:40 +0100 |
---|---|---|
committer | Ferdinand Thiessen <opensource@fthiessen.de> | 2023-11-16 14:25:43 +0100 |
commit | 205801adc6911e0fe368f6cc3a10a559c6aa0ebf (patch) | |
tree | b6b541c844b8fdeca7dab61ca1543d48a23cc7df | |
parent | e250a561701ce010188a3c3a84b522dc51aed878 (diff) | |
download | nextcloud-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.ts | 262 | ||||
-rw-r--r-- | cypress/support/commands.ts | 73 |
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, |