Skip to content
Draft
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
93 changes: 93 additions & 0 deletions cypress/e2e/groupfolders.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ import {
PERMISSION_READ,
PERMISSION_WRITE,
} from './groupfoldersUtils.ts'
import {
openUnifiedSearch,
searchCanLoadMoreResults,
searchFor,
searchHasResult,
} from './unifiedSearchUtils.ts'
import { randHash } from '../utils/index.js'
import { triggerActionForFile } from './files/filesUtils.ts'

Expand Down Expand Up @@ -323,3 +329,90 @@ describe('Groupfolders ACLs and trashbin behavior', () => {
})

})

describe('Groupfolders ACLs and unified search behavior', () => {
let user1: User
let user2: User
let managerUser: User
let groupFolderId: string
let groupName: string
let groupFolderName: string

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

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

createGroup(groupName)
.then(() => {
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
enableACLPermissions(groupFolderId)
addACLManagerUser(groupFolderId, managerUser.userId)
})
})
})
})

it('Search for files in groupfolders with restricted read permissions', () => {
// Create two subfolders and twelve files alterning between subfolders
cy.login(managerUser)
cy.mkdir(managerUser, `/${groupFolderName}/subfolder1`)
cy.mkdir(managerUser, `/${groupFolderName}/subfolder2`)
// Use incremental mtimes to have a specific order in the results
const mtime = Date.now() / 1000
for (let i = 0; i < 12; i = i + 2) {
cy.uploadContent(managerUser, new Blob([i]), 'text/plain', `/${groupFolderName}/subfolder1/test${i}.txt`, mtime + i)
cy.uploadContent(managerUser, new Blob([i + 1]), 'text/plain', `/${groupFolderName}/subfolder2/test${i + 1}.txt`, mtime + i + 1)
}

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

// user1 can find files in both subfolders
cy.login(user1)
cy.visit('/apps/files')
openUnifiedSearch()
searchFor('test')
searchHasResult('Files', `test11.txt in ${groupFolderName}/subfolder2`)
searchHasResult('Files', `test10.txt in ${groupFolderName}/subfolder1`)
searchHasResult('Files', `test9.txt in ${groupFolderName}/subfolder2`)
searchHasResult('Files', `test8.txt in ${groupFolderName}/subfolder1`)
searchHasResult('Files', `test7.txt in ${groupFolderName}/subfolder2`)
searchCanLoadMoreResults('Files')

// user2 can find files only in subfolder1
cy.login(user2)
cy.visit('/apps/files')
openUnifiedSearch()
searchFor('test')
searchHasResult('Files', `test10.txt in ${groupFolderName}/subfolder1`)
searchHasResult('Files', `test8.txt in ${groupFolderName}/subfolder1`)
searchHasResult('Files', `test6.txt in ${groupFolderName}/subfolder1`)
searchHasResult('Files', `test4.txt in ${groupFolderName}/subfolder1`)
searchHasResult('Files', `test2.txt in ${groupFolderName}/subfolder1`)
searchCanLoadMoreResults('Files')
})

})
73 changes: 73 additions & 0 deletions cypress/e2e/unifiedSearchUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

/**
* Get the unified search modal (if open)
*/
export function getUnifiedSearchModal() {
return cy.get('[role="dialog"][id="unified-search"]')
}

/**
* Open the unified search modal
*/
export function openUnifiedSearch() {
cy.get('button[aria-label="Unified search"]').click({ force: true })
// wait for it to be open
getUnifiedSearchModal().should('be.visible')
}

/**
* Searchs for the given string in the unified search modal
*
* @param string term the term to search for
*/
export function searchFor(term: string) {
getUnifiedSearchModal().find('[data-cy-unified-search-input]').type(term)
}

/**
* Get search results main element
*/
export function getUnifiedSearchResults() {
return getUnifiedSearchModal().find('[class="unified-search-modal__results"]')
}

/**
* Get search results list for a specific section
*
* @param string section the section
*/
export function getUnifiedSearchResultsForSection(section: string) {
return getUnifiedSearchResults().contains('[class="result-title"]', section).next('ul')
}

/**
* Get search results footer for a specific section
*
* @param string section the section
*/
export function getUnifiedSearchResultsFooterForSection(section: string) {
return getUnifiedSearchResults().contains('[class="result-title"]', section).siblings('[class="result-footer"]').first()
}

/**
* Checks that the given result is found in the given section
*
* @param string section the section
* @param string result the result in the section
*/
export function searchHasResult(section: string, result: string) {
getUnifiedSearchResultsForSection(section).contains(result).should('be.visible')
}

/**
* Checks that more results can be loaded for the given section
*
* @param string section the section
*/
export function searchCanLoadMoreResults(section: string) {
getUnifiedSearchResultsFooterForSection(section).contains('Load more results').should('be.visible')
}
3 changes: 2 additions & 1 deletion cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,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?) => {
cy.clearCookies()
.then({ timeout: 8000 }, async () => {
const fileName = basename(target)
Expand All @@ -108,6 +108,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,
Expand Down
Loading