diff options
author | skjnldsv <skjnldsv@protonmail.com> | 2024-10-24 15:35:19 +0200 |
---|---|---|
committer | skjnldsv <skjnldsv@protonmail.com> | 2024-10-29 09:08:31 +0100 |
commit | d51cf4536c665ea208ca9bb452ec8841c15a5f35 (patch) | |
tree | 674a9a29a6a671f26b120d9b28da40bfdeca644f /cypress | |
parent | db546e1f55814c4eee8df792a66922bf8d9c926f (diff) | |
download | nextcloud-server-d51cf4536c665ea208ca9bb452ec8841c15a5f35.tar.gz nextcloud-server-d51cf4536c665ea208ca9bb452ec8841c15a5f35.zip |
feat(systemtags): add cypress tests and fix a few logic issues
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
Diffstat (limited to 'cypress')
-rw-r--r-- | cypress/e2e/files/FilesUtils.ts | 27 | ||||
-rw-r--r-- | cypress/e2e/systemtags/files-bulk-action.cy.ts | 354 |
2 files changed, 379 insertions, 2 deletions
diff --git a/cypress/e2e/files/FilesUtils.ts b/cypress/e2e/files/FilesUtils.ts index 0f2b1154200..182972ee44c 100644 --- a/cypress/e2e/files/FilesUtils.ts +++ b/cypress/e2e/files/FilesUtils.ts @@ -14,11 +14,15 @@ export const getActionButtonForFile = (filename: string) => getActionsForFile(fi export const triggerActionForFileId = (fileid: number, actionId: string) => { getActionButtonForFileId(fileid).click() - cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).should('exist').click() + // Getting the last button to avoid the one from popup fading out + cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).last() + .should('exist').click() } export const triggerActionForFile = (filename: string, actionId: string) => { getActionButtonForFile(filename).click() - cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).should('exist').click() + // Getting the last button to avoid the one from popup fading out + cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).last() + .should('exist').click() } export const triggerInlineActionForFileId = (fileid: number, actionId: string) => { @@ -28,6 +32,25 @@ export const triggerInlineActionForFile = (filename: string, actionId: string) = getActionsForFile(filename).get(`button[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`).should('exist').click() } +export const selectAllFiles = () => { + cy.get('[data-cy-files-list-selection-checkbox]').findByRole('checkbox').click({ force: true }) +} +export const selectRowForFile = (filename: string) => { + getRowForFile(filename) + .find('[data-cy-files-list-row-checkbox]') + .findByRole('checkbox') + .click({ 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) + }) + +} + +export const triggerSelectionAction = (actionId: string) => { + cy.get(`button[data-cy-files-list-selection-action="${CSS.escape(actionId)}"]`).should('exist').click() +} + export const moveFile = (fileName: string, dirPath: string) => { getRowForFile(fileName).should('be.visible') triggerActionForFile(fileName, 'move-copy') diff --git a/cypress/e2e/systemtags/files-bulk-action.cy.ts b/cypress/e2e/systemtags/files-bulk-action.cy.ts new file mode 100644 index 00000000000..bfc2280a9d8 --- /dev/null +++ b/cypress/e2e/systemtags/files-bulk-action.cy.ts @@ -0,0 +1,354 @@ +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import type { User } from '@nextcloud/cypress' +import { randomBytes } from 'crypto' +import { getRowForFile, selectAllFiles, selectRowForFile, triggerSelectionAction } from '../files/FilesUtils' +import { createShare } from '../files_sharing/FilesSharingUtils' + +let tags = {} as Record<string, number> +const files = [ + 'file1.txt', + 'file2.txt', + 'file3.txt', + 'file4.txt', + 'file5.txt', +] + +function resetTags() { + tags = {} + for (const tag in [0, 1, 2, 3, 4]) { + tags[randomBytes(8).toString('base64').slice(0, 6)] = 0 + } + + // delete any existing tags + cy.runOccCommand('tag:list --output=json').then((output) => { + Object.keys(JSON.parse(output.stdout)).forEach((id) => { + cy.runOccCommand(`tag:delete ${id}`) + }) + }) + + // create tags + Object.keys(tags).forEach((tag) => { + cy.runOccCommand(`tag:add ${tag} public --output=json`).then((output) => { + tags[tag] = JSON.parse(output.stdout).id as number + }) + }) + cy.log('Using tags', tags) +} + +function expectInlineTagForFile(file: string, tags: string[]) { + getRowForFile(file) + .find('[data-systemtags-fileid]') + .findAllByRole('listitem') + .should('have.length', tags.length) + .each(tag => { + expect(tag.text()).to.be.oneOf(tags) + }) +} + +function triggerTagManagementDialogAction() { + cy.intercept('PROPFIND', '/remote.php/dav/systemtags/').as('getTagsList') + triggerSelectionAction('systemtags:bulk') + cy.wait('@getTagsList') + cy.get('[data-cy-systemtags-picker]').should('be.visible') +} + +describe('Systemtags: Files bulk action', { testIsolation: false }, () => { + let snapshot: string + let user1: User + let user2: User + + before(() => { + cy.createRandomUser().then((_user1) => { + user1 = _user1 + cy.createRandomUser().then((_user2) => { + user2 = _user2 + }) + + files.forEach((file) => { + cy.uploadContent(user1, new Blob([]), 'text/plain', '/' + file) + }) + }) + + resetTags() + }) + + it('Can assign tag to selection', () => { + cy.login(user1) + cy.visit('/apps/files') + + files.forEach((file) => { + getRowForFile(file).should('be.visible') + }) + selectRowForFile('file2.txt') + selectRowForFile('file4.txt') + + triggerTagManagementDialogAction() + cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5) + + cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData') + cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData') + + const tag = Object.keys(tags)[3] + cy.get(`[data-cy-systemtags-picker-tag=${tags[tag]}]`).should('be.visible') + .findByRole('checkbox').click({ force: true }) + cy.get('[data-cy-systemtags-picker-button-submit]').click() + + cy.wait('@getTagData') + cy.wait('@assignTagData') + cy.get('[data-cy-systemtags-picker]').should('not.exist') + + expectInlineTagForFile('file2.txt', [tag]) + expectInlineTagForFile('file4.txt', [tag]) + }) + + it('Can assign multiple tags to selection', () => { + cy.login(user1) + cy.visit('/apps/files') + + files.forEach((file) => { + getRowForFile(file).should('be.visible') + }) + selectAllFiles() + + triggerTagManagementDialogAction() + cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5) + + cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData') + cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData') + + const prevTag = Object.keys(tags)[3] + const tag1 = Object.keys(tags)[1] + const tag2 = Object.keys(tags)[2] + cy.get(`[data-cy-systemtags-picker-tag=${tags[tag1]}]`).should('be.visible') + .findByRole('checkbox').click({ force: true }) + cy.get(`[data-cy-systemtags-picker-tag=${tags[tag2]}]`).should('be.visible') + .findByRole('checkbox').click({ force: true }) + cy.get('[data-cy-systemtags-picker-button-submit]').click() + + cy.wait('@getTagData') + cy.wait('@assignTagData') + cy.get('@getTagData.all').should('have.length', 2) + cy.get('@assignTagData.all').should('have.length', 2) + cy.get('[data-cy-systemtags-picker]').should('not.exist') + + expectInlineTagForFile('file1.txt', [tag1, tag2]) + expectInlineTagForFile('file2.txt', [prevTag, tag1, tag2]) + expectInlineTagForFile('file3.txt', [tag1, tag2]) + expectInlineTagForFile('file4.txt', [prevTag, tag1, tag2]) + expectInlineTagForFile('file5.txt', [tag1, tag2]) + }) + + it('Can remove tag from selection', () => { + cy.login(user1) + cy.visit('/apps/files') + + files.forEach((file) => { + getRowForFile(file).should('be.visible') + }) + selectRowForFile('file1.txt') + selectRowForFile('file3.txt') + selectRowForFile('file4.txt') + + triggerTagManagementDialogAction() + cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5) + + cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData') + cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData') + + const firstTag = Object.keys(tags)[3] + const tag1 = Object.keys(tags)[1] + const tag2 = Object.keys(tags)[2] + cy.get(`[data-cy-systemtags-picker-tag=${tags[tag2]}]`).should('be.visible') + .findByRole('checkbox').click({ force: true }) + cy.get('[data-cy-systemtags-picker-button-submit]').click() + + cy.wait('@getTagData') + cy.wait('@assignTagData') + cy.get('[data-cy-systemtags-picker]').should('not.exist') + + expectInlineTagForFile('file1.txt', [tag1]) + expectInlineTagForFile('file2.txt', [firstTag, tag1, tag2]) + expectInlineTagForFile('file3.txt', [tag1]) + expectInlineTagForFile('file4.txt', [firstTag, tag1]) + expectInlineTagForFile('file5.txt', [tag1, tag2]) + + }) + + it('Can remove multiple tags from selection', () => { + cy.login(user1) + cy.visit('/apps/files') + + files.forEach((file) => { + getRowForFile(file).should('be.visible') + }) + selectAllFiles() + + triggerTagManagementDialogAction() + cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5) + + cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData') + cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData') + + cy.get('[data-cy-systemtags-picker-tag] input:indeterminate').should('exist') + .click({ force: true, multiple: true }) + // indeterminate became checked + cy.get('[data-cy-systemtags-picker-tag] input:checked').should('exist') + .click({ force: true, multiple: true }) + // now all are unchecked + cy.get('[data-cy-systemtags-picker-button-submit]').click() + + cy.wait('@getTagData') + cy.wait('@assignTagData') + cy.get('@getTagData.all').should('have.length', 3) + cy.get('@assignTagData.all').should('have.length', 3) + cy.get('[data-cy-systemtags-picker]').should('not.exist') + + expectInlineTagForFile('file1.txt', []) + expectInlineTagForFile('file2.txt', []) + expectInlineTagForFile('file3.txt', []) + expectInlineTagForFile('file4.txt', []) + expectInlineTagForFile('file5.txt', []) + }) + + it('Can assign and remove multiple tags as a secondary user', () => { + // Create new users + cy.createRandomUser().then((_user1) => { + user1 = _user1 + cy.createRandomUser().then((_user2) => { + user2 = _user2 + }) + + files.forEach((file) => { + cy.uploadContent(user1, new Blob([]), 'text/plain', '/' + file) + }) + }) + + cy.login(user1) + cy.visit('/apps/files') + + files.forEach((file) => { + getRowForFile(file).should('be.visible') + }) + selectAllFiles() + + triggerTagManagementDialogAction() + cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5) + + cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData1') + cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData1') + + const tag1 = Object.keys(tags)[0] + const tag2 = Object.keys(tags)[3] + cy.get(`[data-cy-systemtags-picker-tag=${tags[tag1]}]`).should('be.visible') + .findByRole('checkbox').click({ force: true }) + cy.get(`[data-cy-systemtags-picker-tag=${tags[tag2]}]`).should('be.visible') + .findByRole('checkbox').click({ force: true }) + cy.get('[data-cy-systemtags-picker-button-submit]').click() + + cy.wait('@getTagData1') + cy.wait('@assignTagData1') + cy.get('@getTagData1.all').should('have.length', 2) + cy.get('@assignTagData1.all').should('have.length', 2) + cy.get('[data-cy-systemtags-picker]').should('not.exist') + + expectInlineTagForFile('file1.txt', [tag1, tag2]) + expectInlineTagForFile('file2.txt', [tag1, tag2]) + expectInlineTagForFile('file3.txt', [tag1, tag2]) + expectInlineTagForFile('file4.txt', [tag1, tag2]) + expectInlineTagForFile('file5.txt', [tag1, tag2]) + + createShare('file1.txt', user2.userId) + createShare('file3.txt', user2.userId) + + cy.login(user2) + cy.visit('/apps/files') + + getRowForFile('file1.txt').should('be.visible') + getRowForFile('file3.txt').should('be.visible') + + expectInlineTagForFile('file1.txt', [tag1, tag2]) + expectInlineTagForFile('file3.txt', [tag1, tag2]) + + selectRowForFile('file1.txt') + selectRowForFile('file3.txt') + triggerTagManagementDialogAction() + cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5) + + cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData2') + cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData2') + + cy.get(`[data-cy-systemtags-picker-tag=${tags[tag1]}]`).should('be.visible') + .findByRole('checkbox').click({ force: true }) + cy.get(`[data-cy-systemtags-picker-tag=${tags[tag2]}]`).should('be.visible') + .findByRole('checkbox').click({ force: true }) + cy.get('[data-cy-systemtags-picker-button-submit]').click() + + cy.wait('@getTagData2') + cy.wait('@assignTagData2') + cy.get('@getTagData2.all').should('have.length', 2) + cy.get('@assignTagData2.all').should('have.length', 2) + cy.get('[data-cy-systemtags-picker]').should('not.exist') + + expectInlineTagForFile('file1.txt', []) + expectInlineTagForFile('file3.txt', []) + + cy.login(user1) + cy.visit('/apps/files') + + expectInlineTagForFile('file1.txt', []) + expectInlineTagForFile('file3.txt', []) + }) + + it('Can create tag and assign files to it', () => { + cy.createRandomUser().then((user1) => { + files.forEach((file) => { + cy.uploadContent(user1, new Blob([]), 'text/plain', '/' + file) + }) + + cy.login(user1) + cy.visit('/apps/files') + + files.forEach((file) => { + getRowForFile(file).should('be.visible') + }) + selectAllFiles() + + triggerTagManagementDialogAction() + cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 5) + + cy.intercept('POST', '/remote.php/dav/systemtags').as('createTag') + cy.intercept('PROPFIND', '/remote.php/dav/systemtags/*/files').as('getTagData') + cy.intercept('PROPPATCH', '/remote.php/dav/systemtags/*/files').as('assignTagData') + + const newTag = randomBytes(8).toString('base64').slice(0, 6) + cy.get('[data-cy-systemtags-picker-input]').type(newTag) + cy.get('[data-cy-systemtags-picker-input-submit]').click() + + cy.wait('@createTag') + cy.get('[data-cy-systemtags-picker-tag]').should('have.length', 6) + // Verify the new tag is selected by default + cy.get('[data-cy-systemtags-picker-tag]').contains(newTag) + .parents('[data-cy-systemtags-picker-tag]') + .findByRole('checkbox', { hidden: true }).should('be.checked') + + // Apply changes + cy.get('[data-cy-systemtags-picker-button-submit]').click() + + cy.wait('@getTagData') + cy.wait('@assignTagData') + cy.get('@getTagData.all').should('have.length', 1) + cy.get('@assignTagData.all').should('have.length', 1) + cy.get('[data-cy-systemtags-picker]').should('not.exist') + + expectInlineTagForFile('file1.txt', [newTag]) + expectInlineTagForFile('file2.txt', [newTag]) + expectInlineTagForFile('file3.txt', [newTag]) + expectInlineTagForFile('file4.txt', [newTag]) + expectInlineTagForFile('file5.txt', [newTag]) + }) + }) +}) |