test: adjust cypress tests

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
Ferdinand Thiessen 2025-12-30 22:05:55 +01:00
parent 3726596ad0
commit fd96a32dda
No known key found for this signature in database
GPG key ID: 7E849AE05218500F
10 changed files with 188 additions and 312 deletions

View file

@ -25,9 +25,9 @@ export default defineConfig({
viewportWidth: 1280, viewportWidth: 1280,
viewportHeight: 720, viewportHeight: 720,
// Tries again 2 more times on failure // Tries again when in run mode (cypress run) e.g. on CI
retries: { retries: {
runMode: 2, runMode: 3,
// do not retry in `cypress open` // do not retry in `cypress open`
openMode: 0, openMode: 0,
}, },

View file

@ -24,7 +24,9 @@ export const getActionButtonForFile = (filename: string) => getActionsForFile(fi
export function getActionEntryForFileId(fileid: number, actionId: string) { export function getActionEntryForFileId(fileid: number, actionId: string) {
return getActionButtonForFileId(fileid) return getActionButtonForFileId(fileid)
.should('have.attr', 'aria-controls') .should('have.attr', 'aria-controls')
.then((menuId) => cy.get(`#${menuId}`).find(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`)) .then((menuId) => cy.get(`#${menuId}`)
.should('exist')
.find(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`))
} }
/** /**
@ -33,10 +35,11 @@ export function getActionEntryForFileId(fileid: number, actionId: string) {
* @param actionId * @param actionId
*/ */
export function getActionEntryForFile(file: string, actionId: string) { export function getActionEntryForFile(file: string, actionId: string) {
getActionButtonForFile(file) return getActionButtonForFile(file)
.should('have.attr', 'aria-controls') .should('have.attr', 'aria-controls')
return cy.findByRole('menu') .then((menuId) => cy.get(`#${menuId}`)
.find(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`) .should('exist')
.find(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`))
} }
/** /**
@ -66,9 +69,8 @@ export function getInlineActionEntryForFile(file: string, actionId: string) {
*/ */
export function triggerActionForFileId(fileid: number, actionId: string) { export function triggerActionForFileId(fileid: number, actionId: string) {
getActionButtonForFileId(fileid) getActionButtonForFileId(fileid)
.as('actionButton')
.scrollIntoView() .scrollIntoView()
cy.get('@actionButton') getActionButtonForFileId(fileid)
.click({ force: true }) // force to avoid issues with overlaying file list header .click({ force: true }) // force to avoid issues with overlaying file list header
getActionEntryForFileId(fileid, actionId) getActionEntryForFileId(fileid, actionId)
.find('button') .find('button')
@ -83,9 +85,8 @@ export function triggerActionForFileId(fileid: number, actionId: string) {
*/ */
export function triggerActionForFile(filename: string, actionId: string) { export function triggerActionForFile(filename: string, actionId: string) {
getActionButtonForFile(filename) getActionButtonForFile(filename)
.as('actionButton')
.scrollIntoView() .scrollIntoView()
cy.get('@actionButton') getActionButtonForFile(filename)
.click({ force: true }) // force to avoid issues with overlaying file list header .click({ force: true }) // force to avoid issues with overlaying file list header
getActionEntryForFile(filename, actionId) getActionEntryForFile(filename, actionId)
.find('button') .find('button')
@ -286,8 +287,19 @@ export function navigateToFolder(dirPath: string) {
*/ */
export function closeSidebar() { export function closeSidebar() {
// {force: true} as it might be hidden behind toasts // {force: true} as it might be hidden behind toasts
cy.get('[data-cy-sidebar] .app-sidebar__close').click({ force: true }) cy.get('[data-cy-sidebar] .app-sidebar__close')
cy.get('[data-cy-sidebar]').should('not.be.visible') .click({ force: true })
cy.get('[data-cy-sidebar]')
.should('not.be.visible')
// eslint-disable-next-line cypress/no-unnecessary-waiting -- wait for the animation to finish
cy.wait(500)
cy.url()
.should('not.contain', 'opendetails')
// close all toasts
cy.get('.toast-success')
.if()
.findAllByRole('button')
.click({ force: true, multiple: true })
} }
/** /**

View file

@ -113,6 +113,10 @@ describe('files: Favorites', { testIsolation: true }, () => {
cy.intercept('POST', '**/apps/files/api/v1/files/new%20folder').as('addToFavorites') cy.intercept('POST', '**/apps/files/api/v1/files/new%20folder').as('addToFavorites')
// open sidebar // open sidebar
triggerActionForFile('new folder', 'details') triggerActionForFile('new folder', 'details')
cy.get('[data-cy-sidebar]')
.should('be.visible')
// open sidebar actions
cy.get('[data-cy-sidebar]') cy.get('[data-cy-sidebar]')
.findByRole('button', { name: 'Actions' }) .findByRole('button', { name: 'Actions' })
.click() .click()
@ -121,8 +125,9 @@ describe('files: Favorites', { testIsolation: true }, () => {
.findByRole('menuitem', { name: 'Favorite' }) .findByRole('menuitem', { name: 'Favorite' })
.should('be.visible') .should('be.visible')
.click() .click()
cy.wait('@addToFavorites') cy.wait('@addToFavorites')
// close sidebar
closeSidebar() closeSidebar()
// See favorites star // See favorites star
@ -131,9 +136,14 @@ describe('files: Favorites', { testIsolation: true }, () => {
.should('be.visible') .should('be.visible')
cy.reload() cy.reload()
getRowForFile('new folder')
.should('be.visible')
// can unfavorite // can unfavorite
triggerActionForFile('new folder', 'details') triggerActionForFile('new folder', 'details')
cy.get('[data-cy-sidebar]')
.should('be.visible')
cy.get('[data-cy-sidebar]') cy.get('[data-cy-sidebar]')
.findByRole('button', { name: 'Actions' }) .findByRole('button', { name: 'Actions' })
.click() .click()

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
import { triggerActionForFile } from '../files/FilesUtils.ts' import { closeSidebar, triggerActionForFile } from '../files/FilesUtils.ts'
export interface ShareSetting { export interface ShareSetting {
read: boolean read: boolean
@ -18,6 +18,7 @@ export interface ShareSetting {
export function createShare(fileName: string, username: string, shareSettings: Partial<ShareSetting> = {}) { export function createShare(fileName: string, username: string, shareSettings: Partial<ShareSetting> = {}) {
openSharingPanel(fileName) openSharingPanel(fileName)
cy.intercept('POST', '**/ocs/v2.php/apps/files_sharing/api/v1/shares').as('createShare')
cy.get('#app-sidebar-vue').within(() => { cy.get('#app-sidebar-vue').within(() => {
cy.intercept({ times: 1, method: 'GET', url: '**/apps/files_sharing/api/v1/sharees?*' }).as('userSearch') cy.intercept({ times: 1, method: 'GET', url: '**/apps/files_sharing/api/v1/sharees?*' }).as('userSearch')
@ -30,6 +31,9 @@ export function createShare(fileName: string, username: string, shareSettings: P
// HACK: Save the share and then update it, as permissions changes are currently not saved for new share. // HACK: Save the share and then update it, as permissions changes are currently not saved for new share.
cy.get('[data-cy-files-sharing-share-editor-action="save"]').click({ scrollBehavior: 'nearest' }) cy.get('[data-cy-files-sharing-share-editor-action="save"]').click({ scrollBehavior: 'nearest' })
cy.wait('@createShare')
closeSidebar()
updateShare(fileName, 0, shareSettings) updateShare(fileName, 0, shareSettings)
} }
@ -55,10 +59,16 @@ export function updateShare(fileName: string, index: number, shareSettings: Part
cy.get('[data-cy-files-sharing-share-permissions-checkbox="download"]').find('input').as('downloadCheckbox') cy.get('[data-cy-files-sharing-share-permissions-checkbox="download"]').find('input').as('downloadCheckbox')
if (shareSettings.download) { if (shareSettings.download) {
// Force:true because the checkbox is hidden by the pretty UI. // Force:true because the checkbox is hidden by the pretty UI.
cy.get('@downloadCheckbox').check({ force: true, scrollBehavior: 'nearest' }) cy.get('@downloadCheckbox')
.check({ force: true, scrollBehavior: 'nearest' })
cy.get('@downloadCheckbox')
.should('be.checked')
} else { } else {
// Force:true because the checkbox is hidden by the pretty UI. // Force:true because the checkbox is hidden by the pretty UI.
cy.get('@downloadCheckbox').uncheck({ force: true, scrollBehavior: 'nearest' }) cy.get('@downloadCheckbox')
.uncheck({ force: true, scrollBehavior: 'nearest' })
cy.get('@downloadCheckbox')
.should('not.be.checked')
} }
} }
@ -122,14 +132,16 @@ export function updateShare(fileName: string, index: number, shareSettings: Part
cy.wait('@updateShare') cy.wait('@updateShare')
}) })
// close all toasts closeSidebar()
cy.get('.toast-success').findAllByRole('button').click({ force: true, multiple: true })
} }
export function openSharingPanel(fileName: string) { export function openSharingPanel(fileName: string) {
triggerActionForFile(fileName, 'details') triggerActionForFile(fileName, 'details')
cy.get('[data-cy-sidebar]') cy.get('[data-cy-sidebar]')
.as('sidebar')
.should('be.visible')
cy.get('@sidebar')
.find('[aria-controls="tab-sharing"]') .find('[aria-controls="tab-sharing"]')
.click() .click()
} }

View file

@ -29,8 +29,8 @@ describe('Limit to sharing to people in the same group', () => {
cy.createRandomUser() cy.createRandomUser()
.then((user) => { .then((user) => {
alice = user alice = user
cy.createRandomUser()
}) })
cy.createRandomUser()
.then((user) => { .then((user) => {
bob = user bob = user
@ -49,9 +49,12 @@ describe('Limit to sharing to people in the same group', () => {
cy.login(alice) cy.login(alice)
cy.visit('/apps/files') cy.visit('/apps/files')
createShare(randomFileName1, bob.userId) createShare(randomFileName1, bob.userId)
cy.logout()
cy.login(bob) cy.login(bob)
cy.visit('/apps/files') cy.visit('/apps/files')
createShare(randomFileName2, alice.userId) createShare(randomFileName2, alice.userId)
cy.logout()
}) })
}) })

View file

@ -28,6 +28,9 @@ export function openVersionsPanel(fileName: string) {
triggerActionForFile(basename(fileName), 'details') triggerActionForFile(basename(fileName), 'details')
cy.get('[data-cy-sidebar]') cy.get('[data-cy-sidebar]')
.as('sidebar')
.should('be.visible')
cy.get('@sidebar')
.find('[aria-controls="tab-files_versions"]') .find('[aria-controls="tab-files_versions"]')
.click() .click()
@ -86,7 +89,6 @@ export function setupTestSharedFileFromUser(owner: User, randomFileName: string,
cy.login(owner) cy.login(owner)
cy.visit('/apps/files') cy.visit('/apps/files')
createShare(randomFileName, recipient.userId, shareOptions) createShare(randomFileName, recipient.userId, shareOptions)
cy.logout()
cy.login(recipient) cy.login(recipient)
cy.visit('/apps/files') cy.visit('/apps/files')

View file

@ -6,95 +6,56 @@
import type { User } from '@nextcloud/e2e-test-server/cypress' import type { User } from '@nextcloud/e2e-test-server/cypress'
import { randomString } from '../../support/utils/randomString.ts' import { randomString } from '../../support/utils/randomString.ts'
import { getRowForFile, navigateToFolder } from '../files/FilesUtils.ts' import { navigateToFolder } from '../files/FilesUtils.ts'
import { deleteVersion, doesNotHaveAction, openVersionsPanel, setupTestSharedFileFromUser, uploadThreeVersions } from './filesVersionsUtils.ts' import { deleteVersion, doesNotHaveAction, openVersionsPanel, setupTestSharedFileFromUser, uploadThreeVersions } from './filesVersionsUtils.ts'
describe('Versions restoration', () => { describe('Versions deletion', () => {
const folderName = 'shared_folder' const folderName = 'shared_folder'
const randomFileName = randomString(10) + '.txt' const randomFileName = randomString(10) + '.txt'
const randomFilePath = `/${folderName}/${randomFileName}` const randomFilePath = `/${folderName}/${randomFileName}`
let user: User let user: User
let versionCount = 0 let versionCount = 0
before(() => { beforeEach(() => {
cy.createRandomUser() cy.createRandomUser()
.then((_user) => { .then((_user) => {
user = _user user = _user
cy.mkdir(user, `/${folderName}`) cy.mkdir(user, `/${folderName}`)
uploadThreeVersions(user, randomFilePath) uploadThreeVersions(user, randomFilePath)
uploadThreeVersions(user, randomFilePath) versionCount = 3
versionCount = 6
cy.login(user) cy.login(user)
cy.visit('/apps/files') cy.visit('/apps/files')
navigateToFolder(folderName)
openVersionsPanel(randomFilePath)
}) })
}) })
it('Delete initial version', () => { it('Delete initial version', () => {
navigateToFolder(folderName)
openVersionsPanel(randomFilePath)
cy.get('[data-files-versions-version]')
.should('have.length', versionCount)
deleteVersion(--versionCount)
cy.get('[data-files-versions-version]')
.should('have.length', versionCount)
})
it('Delete versions of shared file with delete permission', () => {
setupTestSharedFileFromUser(user, folderName, { delete: true })
navigateToFolder(folderName)
openVersionsPanel(randomFilePath)
cy.get('[data-files-versions-version]').should('have.length', versionCount) cy.get('[data-files-versions-version]').should('have.length', versionCount)
deleteVersion(2) deleteVersion(--versionCount)
versionCount--
cy.get('[data-files-versions-version]').should('have.length', versionCount) cy.get('[data-files-versions-version]').should('have.length', versionCount)
}) })
context('Delete versions of shared file', () => { it('Delete versions of shared file without delete permission', () => {
it('Works with delete permission', () => { setupTestSharedFileFromUser(user, folderName, { delete: false })
setupTestSharedFileFromUser(user, folderName, { delete: true }) navigateToFolder(folderName)
navigateToFolder(folderName) openVersionsPanel(randomFilePath)
openVersionsPanel(randomFilePath)
cy.get('[data-files-versions-version]').should('have.length', versionCount) doesNotHaveAction(0, 'delete')
deleteVersion(2) doesNotHaveAction(1, 'delete')
versionCount-- doesNotHaveAction(2, 'delete')
cy.get('[data-files-versions-version]').should('have.length', versionCount)
})
it('Does not work without delete permission', () => {
setupTestSharedFileFromUser(user, folderName, { delete: false })
navigateToFolder(folderName)
openVersionsPanel(randomFilePath)
doesNotHaveAction(0, 'delete')
doesNotHaveAction(1, 'delete')
doesNotHaveAction(2, 'delete')
})
it('Does not work without delete permission through direct API access', () => {
let fileId: string | undefined
let versionId: string | undefined
setupTestSharedFileFromUser(user, folderName, { delete: false })
.then((recipient) => {
navigateToFolder(folderName)
openVersionsPanel(randomFilePath)
getRowForFile(randomFileName)
.should('be.visible')
.invoke('attr', 'data-cy-files-list-row-fileid')
.then(($fileId) => { fileId = $fileId })
cy.get('[data-files-versions-version]')
.eq(1)
.invoke('attr', 'data-files-versions-version')
.then(($versionId) => { versionId = $versionId })
cy.logout()
cy.then(() => {
const base = Cypress.config('baseUrl')!.replace(/\/index\.php\/?$/, '')
return cy.request({
method: 'DELETE',
url: `${base}/remote.php/dav/versions/${recipient.userId}/versions/${fileId}/${versionId}`,
auth: { user: recipient.userId, pass: recipient.password },
headers: {
cookie: '',
},
failOnStatusCode: false,
})
}).then(({ status }) => {
expect(status).to.equal(403)
})
})
})
}) })
}) })

View file

@ -6,91 +6,54 @@
import type { User } from '@nextcloud/e2e-test-server/cypress' import type { User } from '@nextcloud/e2e-test-server/cypress'
import { randomString } from '../../support/utils/randomString.ts' import { randomString } from '../../support/utils/randomString.ts'
import { getRowForFile } from '../files/FilesUtils.ts'
import { assertVersionContent, doesNotHaveAction, openVersionsPanel, setupTestSharedFileFromUser, uploadThreeVersions } from './filesVersionsUtils.ts' import { assertVersionContent, doesNotHaveAction, openVersionsPanel, setupTestSharedFileFromUser, uploadThreeVersions } from './filesVersionsUtils.ts'
describe('Versions download', () => { describe('Versions download', () => {
let randomFileName = '' let randomFileName = ''
let user: User let user: User
before(() => { before(() => cy.runOccCommand('config:app:set --value no core shareapi_allow_view_without_download'))
randomFileName = randomString(10) + '.txt'
cy.runOccCommand('config:app:set --value no core shareapi_allow_view_without_download')
cy.createRandomUser()
.then((_user) => {
user = _user
uploadThreeVersions(user, randomFileName)
cy.login(user)
cy.visit('/apps/files')
openVersionsPanel(randomFileName)
})
})
after(() => { after(() => {
cy.runOccCommand('config:app:delete core shareapi_allow_view_without_download') cy.runOccCommand('config:app:delete core shareapi_allow_view_without_download')
}) })
beforeEach(() => {
randomFileName = randomString(10) + '.txt'
cy.createRandomUser()
.then((_user) => {
user = _user
uploadThreeVersions(user, randomFileName)
})
})
it('Download versions and assert their content', () => { it('Download versions and assert their content', () => {
cy.login(user)
cy.visit('/apps/files')
openVersionsPanel(randomFileName)
assertVersionContent(0, 'v3') assertVersionContent(0, 'v3')
assertVersionContent(1, 'v2') assertVersionContent(1, 'v2')
assertVersionContent(2, 'v1') assertVersionContent(2, 'v1')
}) })
context('Download versions of shared file', () => { it('Download versions of shared file with download permission', () => {
it('Works with download permission', () => { setupTestSharedFileFromUser(user, randomFileName, { download: true })
setupTestSharedFileFromUser(user, randomFileName, { download: true }) openVersionsPanel(randomFileName)
openVersionsPanel(randomFileName)
assertVersionContent(0, 'v3') assertVersionContent(0, 'v3')
assertVersionContent(1, 'v2') assertVersionContent(1, 'v2')
assertVersionContent(2, 'v1') assertVersionContent(2, 'v1')
}) })
it('Does not show action without download permission', () => { it('Does not show action without download permission', () => {
setupTestSharedFileFromUser(user, randomFileName, { download: false }) setupTestSharedFileFromUser(user, randomFileName, { download: false })
openVersionsPanel(randomFileName) openVersionsPanel(randomFileName)
cy.get('[data-files-versions-version]').eq(0).find('.action-item__menutoggle').should('not.exist') cy.get('[data-files-versions-version]').eq(0).find('.action-item__menutoggle').should('not.exist')
cy.get('[data-files-versions-version]').eq(0).get('[data-cy-version-action="download"]').should('not.exist') cy.get('[data-files-versions-version]').eq(0).get('[data-cy-version-action="download"]').should('not.exist')
doesNotHaveAction(1, 'download') doesNotHaveAction(1, 'download')
doesNotHaveAction(2, 'download') doesNotHaveAction(2, 'download')
})
it('Does not work without download permission through direct API access', () => {
let fileId: string | undefined
let versionId: string | undefined
setupTestSharedFileFromUser(user, randomFileName, { download: false })
.then((recipient) => {
openVersionsPanel(randomFileName)
getRowForFile(randomFileName)
.should('be.visible')
.invoke('attr', 'data-cy-files-list-row-fileid')
.then(($fileId) => { fileId = $fileId })
cy.get('[data-files-versions-version]')
.eq(1)
.invoke('attr', 'data-files-versions-version')
.then(($versionId) => { versionId = $versionId })
cy.logout()
cy.then(() => {
const base = Cypress.config('baseUrl')!.replace(/\/index\.php\/?$/, '')
return cy.request({
url: `${base}/remote.php/dav/versions/${recipient.userId}/versions/${fileId}/${versionId}`,
auth: { user: recipient.userId, pass: recipient.password },
headers: {
cookie: '',
},
failOnStatusCode: false,
})
}).then(({ status }) => {
expect(status).to.equal(403)
})
})
})
}) })
}) })

View file

@ -6,27 +6,30 @@
import type { User } from '@nextcloud/e2e-test-server/cypress' import type { User } from '@nextcloud/e2e-test-server/cypress'
import { randomString } from '../../support/utils/randomString.ts' import { randomString } from '../../support/utils/randomString.ts'
import { getRowForFile } from '../files/FilesUtils.ts' import { navigateToFolder } from '../files/FilesUtils.ts'
import { doesNotHaveAction, nameVersion, openVersionsPanel, setupTestSharedFileFromUser, uploadThreeVersions } from './filesVersionsUtils.ts' import { doesNotHaveAction, nameVersion, openVersionsPanel, setupTestSharedFileFromUser, uploadThreeVersions } from './filesVersionsUtils.ts'
describe('Versions naming', () => { describe('Versions naming', () => {
let randomFileName = '' let randomFileName = ''
let user: User let user: User
before(() => { beforeEach(() => {
randomFileName = randomString(10) + '.txt' randomFileName = randomString(10) + '.txt'
cy.createRandomUser() cy.createRandomUser()
.then((_user) => { .then((_user) => {
user = _user user = _user
uploadThreeVersions(user, randomFileName) cy.mkdir(_user, '/share')
cy.login(user) uploadThreeVersions(user, `share/${randomFileName}`)
cy.visit('/apps/files')
openVersionsPanel(randomFileName)
}) })
}) })
it('Names the versions', () => { it('Names the versions', () => {
cy.login(user)
cy.visit('/apps/files')
navigateToFolder('share')
openVersionsPanel(randomFileName)
nameVersion(2, 'v1') nameVersion(2, 'v1')
cy.get('#tab-files_versions').within(() => { cy.get('#tab-files_versions').within(() => {
cy.get('[data-files-versions-version]').eq(2).contains('v1') cy.get('[data-files-versions-version]').eq(2).contains('v1')
@ -44,92 +47,45 @@ describe('Versions naming', () => {
}) })
}) })
context('Name versions of shared file', () => { it('Name versions of shared file with edit permission', () => {
context('with edit permission', () => { setupTestSharedFileFromUser(user, 'share', { update: true })
before(() => {
setupTestSharedFileFromUser(user, randomFileName, { update: true })
openVersionsPanel(randomFileName)
})
it('Names the versions', () => { navigateToFolder('share')
nameVersion(2, 'v1 - shared') openVersionsPanel(randomFileName)
cy.get('#tab-files_versions').within(() => {
cy.get('[data-files-versions-version]').eq(2).contains('v1 - shared')
cy.get('[data-files-versions-version]').eq(2).contains('Initial version').should('not.exist')
})
nameVersion(1, 'v2 - shared') nameVersion(2, 'v1 - shared')
cy.get('#tab-files_versions').within(() => { cy.get('#tab-files_versions').within(() => {
cy.get('[data-files-versions-version]').eq(1).contains('v2 - shared') cy.get('[data-files-versions-version]').eq(2).contains('v1 - shared')
}) cy.get('[data-files-versions-version]').eq(2).contains('Initial version').should('not.exist')
nameVersion(0, 'v3 - shared')
cy.get('#tab-files_versions').within(() => {
cy.get('[data-files-versions-version]').eq(0).contains('v3 - shared (Current version)')
})
})
}) })
context('without edit permission', () => { nameVersion(1, 'v2 - shared')
let recipient: User cy.get('#tab-files_versions').within(() => {
cy.get('[data-files-versions-version]').eq(1).contains('v2 - shared')
})
beforeEach(() => { nameVersion(0, 'v3 - shared')
setupTestSharedFileFromUser(user, randomFileName, { update: false }) cy.get('#tab-files_versions').within(() => {
.then(($recipient) => { cy.get('[data-files-versions-version]').eq(0).contains('v3 - shared (Current version)')
recipient = $recipient
openVersionsPanel(randomFileName)
})
})
it('Does not show action', () => {
cy.get('[data-files-versions-version]').eq(0).find('.action-item__menutoggle').should('not.exist')
cy.get('[data-files-versions-version]').eq(0).get('[data-cy-version-action="label"]').should('not.exist')
doesNotHaveAction(1, 'label')
doesNotHaveAction(2, 'label')
})
it('Does not work without update permission through direct API access', () => {
let fileId: string | undefined
let versionId: string | undefined
getRowForFile(randomFileName)
.should('be.visible')
.invoke('attr', 'data-cy-files-list-row-fileid')
.then(($fileId) => { fileId = $fileId })
cy.get('[data-files-versions-version]')
.eq(1)
.invoke('attr', 'data-files-versions-version')
.then(($versionId) => { versionId = $versionId })
cy.logout()
cy.then(() => {
const base = Cypress.config('baseUrl')!.replace(/index\.php\/?/, '')
return cy.request({
method: 'PROPPATCH',
url: `${base}/remote.php/dav/versions/${recipient.userId}/versions/${fileId}/${versionId}`,
auth: { user: recipient.userId, pass: recipient.password },
headers: {
cookie: '',
},
body: `<?xml version="1.0"?>
<d:propertyupdate xmlns:d="DAV:"
xmlns:oc="http://owncloud.org/ns"
xmlns:nc="http://nextcloud.org/ns"
xmlns:ocs="http://open-collaboration-services.org/ns">
<d:set>
<d:prop>
<nc:version-label>not authorized labeling</nc:version-label>
</d:prop>
</d:set>
</d:propertyupdate>`,
failOnStatusCode: false,
})
}).then(({ status }) => {
expect(status).to.equal(403)
})
})
}) })
}) })
it('Name versions without edit permission fails', () => {
setupTestSharedFileFromUser(user, 'share', { update: false })
navigateToFolder('share')
openVersionsPanel(randomFileName)
cy.get('[data-files-versions-version]')
.eq(0)
.as('firstVersion')
.find('.action-item__menutoggle')
.should('not.exist')
cy.get('@firstVersion')
.find('[data-cy-version-action="label"]')
.should('not.exist')
doesNotHaveAction(1, 'label')
doesNotHaveAction(2, 'label')
})
}) })

View file

@ -6,31 +6,31 @@
import type { User } from '@nextcloud/e2e-test-server/cypress' import type { User } from '@nextcloud/e2e-test-server/cypress'
import { randomString } from '../../support/utils/randomString.ts' import { randomString } from '../../support/utils/randomString.ts'
import { getRowForFile } from '../files/FilesUtils.ts' import { navigateToFolder } from '../files/FilesUtils.ts'
import { assertVersionContent, doesNotHaveAction, openVersionsPanel, restoreVersion, setupTestSharedFileFromUser, uploadThreeVersions } from './filesVersionsUtils.ts' import { assertVersionContent, doesNotHaveAction, openVersionsPanel, restoreVersion, setupTestSharedFileFromUser, uploadThreeVersions } from './filesVersionsUtils.ts'
describe('Versions restoration', () => { describe('Versions restoration', () => {
let randomFileName = '' let randomFileName = ''
let user: User let user: User
before(() => { beforeEach(() => {
randomFileName = randomString(10) + '.txt' randomFileName = randomString(10) + '.txt'
cy.createRandomUser() cy.createRandomUser()
.then((_user) => { .then((_user) => {
user = _user user = _user
uploadThreeVersions(user, randomFileName) cy.mkdir(_user, '/share')
uploadThreeVersions(user, `share/${randomFileName}`)
cy.login(user) cy.login(user)
cy.visit('/apps/files') cy.visit('/apps/files')
openVersionsPanel(randomFileName)
}) })
}) })
it('Current version does not have restore action', () => {
doesNotHaveAction(0, 'restore')
})
it('Restores initial version', () => { it('Restores initial version', () => {
navigateToFolder('share')
openVersionsPanel(randomFileName)
// Current version does not have restore action
doesNotHaveAction(0, 'restore')
restoreVersion(2) restoreVersion(2)
cy.get('#tab-files_versions').within(() => { cy.get('#tab-files_versions').within(() => {
@ -38,81 +38,38 @@ describe('Versions restoration', () => {
cy.get('[data-files-versions-version]').eq(0).contains('Current version') cy.get('[data-files-versions-version]').eq(0).contains('Current version')
cy.get('[data-files-versions-version]').eq(2).contains('Initial version').should('not.exist') cy.get('[data-files-versions-version]').eq(2).contains('Initial version').should('not.exist')
}) })
})
it('Downloads versions and assert there content', () => { // Downloads versions and assert there content
assertVersionContent(0, 'v1') assertVersionContent(0, 'v1')
assertVersionContent(1, 'v3') assertVersionContent(1, 'v3')
assertVersionContent(2, 'v2') assertVersionContent(2, 'v2')
}) })
context('Restore versions of shared file', () => { it('Restore versions of shared file with update permission', () => {
it('Works with update permission', () => { setupTestSharedFileFromUser(user, 'share', { update: true })
setupTestSharedFileFromUser(user, randomFileName, { update: true }) navigateToFolder('share')
openVersionsPanel(randomFileName) openVersionsPanel(randomFileName)
it('Restores initial version', () => { restoreVersion(2)
restoreVersion(2) cy.get('#tab-files_versions').within(() => {
cy.get('#tab-files_versions').within(() => { cy.get('[data-files-versions-version]').should('have.length', 3)
cy.get('[data-files-versions-version]').should('have.length', 3) cy.get('[data-files-versions-version]').eq(0).contains('Current version')
cy.get('[data-files-versions-version]').eq(0).contains('Current version') cy.get('[data-files-versions-version]').eq(2).contains('Initial version').should('not.exist')
cy.get('[data-files-versions-version]').eq(2).contains('Initial version').should('not.exist')
})
})
it('Downloads versions and assert there content', () => {
assertVersionContent(0, 'v1')
assertVersionContent(1, 'v3')
assertVersionContent(2, 'v2')
})
}) })
assertVersionContent(0, 'v1')
assertVersionContent(1, 'v3')
assertVersionContent(2, 'v2')
})
it('Does not show action without delete permission', () => { it('Does not show action without delete permission', () => {
setupTestSharedFileFromUser(user, randomFileName, { update: false }) setupTestSharedFileFromUser(user, 'share', { update: false })
openVersionsPanel(randomFileName) navigateToFolder('share')
openVersionsPanel(randomFileName)
cy.get('[data-files-versions-version]').eq(0).find('.action-item__menutoggle').should('not.exist') cy.get('[data-files-versions-version]').eq(0).find('.action-item__menutoggle').should('not.exist')
cy.get('[data-files-versions-version]').eq(0).get('[data-cy-version-action="restore"]').should('not.exist') cy.get('[data-files-versions-version]').eq(0).get('[data-cy-version-action="restore"]').should('not.exist')
doesNotHaveAction(1, 'restore') doesNotHaveAction(1, 'restore')
doesNotHaveAction(2, 'restore') doesNotHaveAction(2, 'restore')
})
it('Does not work without update permission through direct API access', () => {
let fileId: string | undefined
let versionId: string | undefined
setupTestSharedFileFromUser(user, randomFileName, { update: false })
.then((recipient) => {
openVersionsPanel(randomFileName)
getRowForFile(randomFileName)
.should('be.visible')
.invoke('attr', 'data-cy-files-list-row-fileid')
.then(($fileId) => { fileId = $fileId })
cy.get('[data-files-versions-version]')
.eq(1)
.invoke('attr', 'data-files-versions-version')
.then(($versionId) => { versionId = $versionId })
cy.logout()
cy.then(() => {
const base = Cypress.config('baseUrl')!.replace(/\/index\.php\/?$/, '')
return cy.request({
method: 'MOVE',
url: `${base}/remote.php/dav/versions/${recipient.userId}/versions/${fileId}/${versionId}`,
auth: { user: recipient.userId, pass: recipient.password },
headers: {
cookie: '',
Destination: `${base}}/remote.php/dav/versions/${recipient.userId}/restore/target`,
},
failOnStatusCode: false,
})
}).then(({ status }) => {
expect(status).to.equal(403)
})
})
})
}) })
}) })