aboutsummaryrefslogtreecommitdiffstats
path: root/cypress
diff options
context:
space:
mode:
authorskjnldsv <skjnldsv@protonmail.com>2024-10-24 15:35:19 +0200
committerskjnldsv <skjnldsv@protonmail.com>2024-10-29 09:08:31 +0100
commitd51cf4536c665ea208ca9bb452ec8841c15a5f35 (patch)
tree674a9a29a6a671f26b120d9b28da40bfdeca644f /cypress
parentdb546e1f55814c4eee8df792a66922bf8d9c926f (diff)
downloadnextcloud-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.ts27
-rw-r--r--cypress/e2e/systemtags/files-bulk-action.cy.ts354
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])
+ })
+ })
+})