Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cypress test for ACLs and trashbin #2650

Merged
merged 2 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cypress/dockerNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export const configureNextcloud = async function(branch = 'master') {
// Enable the app and give status
await runExec(container, ['php', 'occ', 'app:enable', '--force', 'viewer'], true)
await runExec(container, ['php', 'occ', 'app:enable', 'groupfolders', '--force'], true)
await runExec(container, ['php', 'occ', 'app:enable', 'files_trashbin', '--force'], true)
// await runExec(container, ['php', 'occ', 'app:list'], true)

console.log('└─ Nextcloud is now ready to use 🎉')
Expand Down
220 changes: 206 additions & 14 deletions cypress/e2e/groupfolders.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,22 @@
*
*/
import {
addACLManagerUser,
addUserToGroup,
createGroup,
createGroupFolder,
deleteGroupFolder,
deleteFile,
enableACLPermissions,
enterFolder,
enterFolderInTrashbin,
fileOrFolderExists,
fileOrFolderDoesNotExist,
fileOrFolderExistsInTrashbin,
fileOrFolderDoesNotExistInTrashbin,
restoreFile,
setACLPermissions,
PERMISSION_DELETE,
PERMISSION_READ,
PERMISSION_WRITE,
} from './groupfoldersUtils'
Expand All @@ -32,40 +44,220 @@ import { randHash } from '../utils'

import type { User } from '@nextcloud/cypress'

describe('Manage groupfolders', () => {
let user: User
describe('Groupfolders ACLs and trashbin behavior', () => {
let user1: User
let user2: User
let managerUser: User
let groupFolderId: string
let groupName: string
let groupFolderName: string

before(() => {
beforeEach(() => {
if (groupFolderId) {
deleteGroupFolder(groupFolderId)
}
groupName = `test_group_${randHash()}`
groupFolderName = `test_group_folder_${randHash()}`

cy.createRandomUser()
.then(_user => {
user = _user
cy.login(user)
user1 = _user
})
cy.createRandomUser()
.then(_user => {
user2 = _user
})
cy.createRandomUser()
.then(_user => {
managerUser = _user

createGroup(groupName)
.then(() => {
addUserToGroup(groupName, user.userId)
createGroupFolder(groupFolderName, groupName, [PERMISSION_READ, PERMISSION_WRITE])
addUserToGroup(groupName, user1.userId)
addUserToGroup(groupName, user2.userId)
addUserToGroup(groupName, managerUser.userId)
createGroupFolder(groupFolderName, groupName, [PERMISSION_READ, PERMISSION_WRITE, PERMISSION_DELETE])
.then(_groupFolderId => {
groupFolderId = _groupFolderId
cy.visit('/apps/files')
enableACLPermissions(groupFolderId)
addACLManagerUser(groupFolderId,managerUser.userId)
})
})
})
})

after(() => {
if (groupFolderId) {
deleteGroupFolder(groupFolderId)
}
it('ACL, delete and restore', () => {
// Create two subfolders and two files as manager
cy.login(managerUser)
cy.mkdir(managerUser, `/${groupFolderName}/subfolder1`)
cy.mkdir(managerUser, `/${groupFolderName}/subfolder1/subfolder2`)
cy.uploadContent(managerUser, new Blob(['Content of the file']), 'text/plain', `/${groupFolderName}/subfolder1/file1.txt`)
cy.uploadContent(managerUser, new Blob(['Content of the file']), 'text/plain', `/${groupFolderName}/subfolder1/subfolder2/file2.txt`)

// Set ACL permissions
setACLPermissions(groupFolderId, '/subfolder1', [`+${PERMISSION_READ}`,`-${PERMISSION_WRITE}`], undefined, user1.userId)
setACLPermissions(groupFolderId, '/subfolder1', [`-${PERMISSION_READ}`], undefined, user2.userId)

// User1 has access
cy.login(user1)
cy.visit('/apps/files')
enterFolder(groupFolderName)
enterFolder('subfolder1')
fileOrFolderExists('file1.txt')
enterFolder('subfolder2')
fileOrFolderExists('file2.txt')

// User2 has no access
cy.login(user2)
cy.visit('/apps/files')
enterFolder(groupFolderName)
fileOrFolderDoesNotExist('subfolder1')

// Delete files
cy.login(managerUser)
cy.visit('/apps/files')
enterFolder(groupFolderName)
enterFolder('subfolder1')
deleteFile('file1.txt')
deleteFile('subfolder2')

// User1 sees it in trash
cy.login(user1)
cy.visit('/apps/files/trashbin')
fileOrFolderExistsInTrashbin('file1.txt')
enterFolderInTrashbin('subfolder2')
fileOrFolderExists('file2.txt')

// User2 does not
cy.login(user2)
cy.visit('/apps/files/trashbin')
fileOrFolderDoesNotExistInTrashbin('file1.txt')
fileOrFolderDoesNotExistInTrashbin('subfolder2')

// Restore files
cy.login(managerUser)
cy.visit('/apps/files/trashbin')
fileOrFolderExistsInTrashbin('file1.txt')
fileOrFolderExistsInTrashbin('subfolder2')
restoreFile('file1.txt')
restoreFile('subfolder2')

// User1 has access
cy.login(user1)
cy.visit('/apps/files')
enterFolder(groupFolderName)
fileOrFolderExists('subfolder1')
enterFolder('subfolder1')
fileOrFolderExists('file1.txt')
enterFolder('subfolder2')
fileOrFolderExists('file2.txt')

// User2 has no access
cy.login(user2)
cy.visit('/apps/files')
enterFolder(groupFolderName)
fileOrFolderDoesNotExist('subfolder1')
})

it.skip('ACL directly on deleted folder', () => {
// Create a subfolders and a file as manager
cy.login(managerUser)
cy.mkdir(managerUser, `/${groupFolderName}/subfolder1`)
cy.uploadContent(managerUser, new Blob(['Content of the file']), 'text/plain', `/${groupFolderName}/subfolder1/file1.txt`)

// Set ACL permissions on subfolder
setACLPermissions(groupFolderId, '/subfolder1', [`+${PERMISSION_READ}`,`-${PERMISSION_WRITE}`], undefined, user1.userId)
setACLPermissions(groupFolderId, '/subfolder1', [`-${PERMISSION_READ}`], undefined, user2.userId)

// Delete subfolder
cy.login(managerUser)
cy.visit('/apps/files')
enterFolder(groupFolderName)
deleteFile('subfolder1')

// User1 sees it in trash
cy.login(user1)
cy.visit('/apps/files/trashbin')
fileOrFolderExistsInTrashbin('subfolder1')
enterFolderInTrashbin('subfolder1')
fileOrFolderExists('file1.txt')

// User2 does not
cy.login(user2)
cy.visit('/apps/files/trashbin')
fileOrFolderDoesNotExistInTrashbin('subfolder1')
})

it('Visite the group folder', () => {
return true
it.skip('Delete, rename parent and restore', () => {
// Create a subfolders and a file as manager
cy.login(managerUser)
cy.mkdir(managerUser, `/${groupFolderName}/subfolder1`)
cy.uploadContent(managerUser, new Blob(['Content of the file']), 'text/plain', `/${groupFolderName}/subfolder1/file1.txt`)

// Delete file
cy.login(managerUser)
cy.visit('/apps/files')
enterFolder(groupFolderName)
enterFolder('subfolder1')
deleteFile('file1.txt')

// Rename subfolder1
cy.visit('/apps/files')
enterFolder(groupFolderName)
cy.get(`[data-cy-files-list] [data-cy-files-list-row-name="subfolder1"] [data-cy-files-list-row-actions]`).click()
cy.get(`[data-cy-files-list] [data-cy-files-list-row-action="rename"]`).scrollIntoView()
cy.get(`[data-cy-files-list] [data-cy-files-list-row-action="rename"]`).click()
cy.get(`[data-cy-files-list] [data-cy-files-list-row-name="subfolder1"] [class="files-list__row-rename"] [class="input-field__input"]`).type('subfolder1renamed{enter}')
fileOrFolderExists('subfolder1renamed')

// Restore from trash
cy.visit('/apps/files/trashbin')
restoreFile('file1.txt')

// File should be restored in renamed folder
cy.login(managerUser)
cy.visit('/apps/files')
enterFolder(groupFolderName)
fileOrFolderExists('subfolder1renamed')
fileOrFolderDoesNotExist('file1.txt')
enterFolder('subfolder1renamed')
fileOrFolderExists('file1.txt')
})

it.skip('Delete, rename parent and check ACL', () => {
// Create a subfolders and a file as manager
cy.login(managerUser)
cy.mkdir(managerUser, `/${groupFolderName}/subfolder1`)
cy.uploadContent(managerUser, new Blob(['Content of the file']), 'text/plain', `/${groupFolderName}/subfolder1/file1.txt`)

// Set ACL permissions
setACLPermissions(groupFolderId, '/subfolder1', [`+${PERMISSION_READ}`,`-${PERMISSION_WRITE}`], undefined, user1.userId)
setACLPermissions(groupFolderId, '/subfolder1', [`-${PERMISSION_READ}`], undefined, user2.userId)

// Delete file
cy.login(managerUser)
cy.visit('/apps/files')
enterFolder(groupFolderName)
enterFolder('subfolder1')
deleteFile('file1.txt')

// Rename subfolder1
cy.visit('/apps/files')
enterFolder(groupFolderName)
cy.get(`[data-cy-files-list] [data-cy-files-list-row-name="subfolder1"] [data-cy-files-list-row-actions]`).click()
cy.get(`[data-cy-files-list] [data-cy-files-list-row-action="rename"]`).scrollIntoView()
cy.get(`[data-cy-files-list] [data-cy-files-list-row-action="rename"]`).click()
cy.get(`[data-cy-files-list] [data-cy-files-list-row-name="subfolder1"] [class="files-list__row-rename"] [class="input-field__input"]`).type('subfolder1renamed{enter}')
fileOrFolderExists('subfolder1renamed')

// User1 sees it in trash
cy.login(user1)
cy.visit('/apps/files/trashbin')
fileOrFolderExistsInTrashbin('file1.txt')

// User2 does not
cy.login(user2)
cy.visit('/apps/files/trashbin')
fileOrFolderDoesNotExistInTrashbin('file1.txt')
})
})
44 changes: 41 additions & 3 deletions cypress/e2e/groupfoldersUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ export function disableACLPermissions(groupFolderId: string) {
return cy.runOccCommand(`groupfolders:permissions ${groupFolderId} --disable`)
}

export function addACLManager(groupFolderId: string, groupOrUserName: string) {
return cy.runOccCommand(`groupfolders:permissions ${groupFolderId} --manage-add ${groupOrUserName}`)
export function addACLManagerUser(groupFolderId: string, userName: string) {
return cy.runOccCommand(`groupfolders:permissions ${groupFolderId} --manage-add --user ${userName}`)
}

export function removeACLManager(groupFolderId: string, groupOrUserName: string) {
Expand All @@ -67,9 +67,47 @@ export function setACLPermissions(
userId?: string,
) {
const target = groupId !== undefined ? `--group ${groupId}` : `--user ${userId}`
return cy.runOccCommand(`groupfolders:permissions ${groupFolderId} ${path} ${aclPermissions} ${target}`)
return cy.runOccCommand(`groupfolders:permissions ${groupFolderId} ${path} ${target} -- ${aclPermissions.join(' ')}`)
}

export function deleteGroupFolder(groupFolderId: string) {
return cy.runOccCommand(`groupfolders:delete ${groupFolderId}`)
}

export function fileOrFolderExists(name: string) {
cy.get(`[data-cy-files-list] [data-cy-files-list-row-name="${name}"]`).should('be.visible')
}

export function fileOrFolderDoesNotExist(name: string) {
// Make sure file list is loaded first
cy.get(`[data-cy-files-list-tfoot],[data-cy-files-content-empty]`).should('be.visible')
cy.get(`[data-cy-files-list] [data-cy-files-list-row-name="${name}"]`).should('not.exist')
}

export function fileOrFolderExistsInTrashbin(name: string) {
cy.get(`[data-cy-files-list] [data-cy-files-list-row-name^="${name}.d"]`).should('be.visible')
}

export function fileOrFolderDoesNotExistInTrashbin(name: string) {
// Make sure file list is loaded first
cy.get(`[data-cy-files-list-tfoot],[data-cy-files-content-empty]`).should('be.visible')
cy.get(`[data-cy-files-list] [data-cy-files-list-row-name^="${name}.d"]`).should('not.exist')
}

export function enterFolder(name: string) {
cy.get(`[data-cy-files-list] [data-cy-files-list-row-name="${name}"]`).click()
}

export function enterFolderInTrashbin(name: string) {
cy.get(`[data-cy-files-list] [data-cy-files-list-row-name^="${name}.d"]`).click()
}

export function deleteFile(name: string) {
cy.get(`[data-cy-files-list] [data-cy-files-list-row-name="${name}"] [data-cy-files-list-row-actions]`).click()
cy.get(`[data-cy-files-list] [data-cy-files-list-row-action="delete"]`).scrollIntoView()
cy.get(`[data-cy-files-list] [data-cy-files-list-row-action="delete"]`).click()
}

export function restoreFile(name: string) {
cy.get(`[data-cy-files-list] [data-cy-files-list-row-name^="${name}.d"] [data-cy-files-list-row-action="restore"]`).click()
}
32 changes: 31 additions & 1 deletion cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ declare global {
*/
uploadContent(user: User, content: Blob, mimeType: string, target: string): Cypress.Chainable<void>,

/**
* Create a new directory
* **Warning**: Using this function will reset the previous session
*/
mkdir(user: User, target: string): Cypress.Chainable<void>,

/**
* Run an occ command in the docker container.
*/
Expand All @@ -56,6 +62,30 @@ declare global {
const url = (Cypress.config('baseUrl') || '').replace(/\/index.php\/?$/g, '')
Cypress.env('baseUrl', url)


Cypress.Commands.add('mkdir', (user: User, target: string) => {
// eslint-disable-next-line cypress/unsafe-to-chain-command
cy.clearCookies()
.then({timeout:8000}, 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.uploadedFile - uploads a file from the fixtures folder
* TODO: standardise in @nextcloud/cypress
Expand Down Expand Up @@ -85,7 +115,7 @@ Cypress.Commands.add('uploadFile', (user, fixture = 'image.jpg', mimeType = 'ima
*/
Cypress.Commands.add('uploadContent', (user, blob, mimeType, target) => {
cy.clearCookies()
.then(async () => {
.then({timeout:8000}, async () => {
const fileName = basename(target)

// Process paths
Expand Down
Loading