diff --git a/.drone.star b/.drone.star index 0cc995a2bde..fd4daa08dbf 100644 --- a/.drone.star +++ b/.drone.star @@ -99,7 +99,6 @@ config = { "webUIPreview", "webUILogin", ], - "webUIWebdavLockProtection": "oCISWebdavLockProtection", "oCISSharingBasic": [ "webUISharingAcceptShares", ], @@ -219,7 +218,6 @@ basicTestSuites = [ "webUITrashbinFilesFolders", "webUITrashbinRestore", "webUIUpload", - "webUIWebdavLockProtection", ] ocisSpecificTestSuites = [ diff --git a/tests/acceptance/expected-failures-with-ocis-server-ocis-storage.md b/tests/acceptance/expected-failures-with-ocis-server-ocis-storage.md index 441bc100226..5686ecb60da 100644 --- a/tests/acceptance/expected-failures-with-ocis-server-ocis-storage.md +++ b/tests/acceptance/expected-failures-with-ocis-server-ocis-storage.md @@ -21,23 +21,6 @@ Other free text and markdown formatting can be used elsewhere in the document if - [webUISharingPublicManagement/shareByPublicLink.feature:24](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUISharingPublicManagement/shareByPublicLink.feature#L24) -### [Resources cannot be locked under ocis](https://github.com/owncloud/ocis/issues/1284) - -- [webUIWebdavLockProtection/delete.feature:33](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIWebdavLockProtection/delete.feature#L33) -- [webUIWebdavLockProtection/delete.feature:34](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIWebdavLockProtection/delete.feature#L34) -- [webUIWebdavLockProtection/move.feature:36](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIWebdavLockProtection/move.feature#L36) -- [webUIWebdavLockProtection/move.feature:37](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIWebdavLockProtection/move.feature#L37) -- [webUIWebdavLockProtection/upload.feature:32](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIWebdavLockProtection/upload.feature#L32) - -### [Resources cannot be locked under ocis](https://github.com/owncloud/ocis/issues/1284) - -- [webUIWebdavLockProtection/upload.feature:33](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIWebdavLockProtection/upload.feature#L33) - -### [Writing to locked files/folders give only a generic error message](https://github.com/owncloud/web/issues/5741) - -- [webUIWebdavLockProtection/upload.feature:32](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIWebdavLockProtection/upload.feature#L32) -- [webUIWebdavLockProtection/upload.feature:33](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIWebdavLockProtection/upload.feature#L33) - ### [empty subfolder inside a folder to be uploaded is not created on the server](https://github.com/owncloud/web/issues/6348) - [webUIUpload/upload.feature:43](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIUpload/upload.feature#L43) diff --git a/tests/acceptance/features/webUIWebdavLockProtection/delete.feature b/tests/acceptance/features/webUIWebdavLockProtection/delete.feature deleted file mode 100644 index 88f6fa53a09..00000000000 --- a/tests/acceptance/features/webUIWebdavLockProtection/delete.feature +++ /dev/null @@ -1,34 +0,0 @@ -Feature: Locks - As a user - I would like to be able to use locks control deletion of files and folders - So that I can prevent files and folders being deleted while they are being used by another user - - Background: - #do not set email, see bugs in https://github.com/owncloud/core/pull/32250#issuecomment-434615887 - Given these users have been created with default attributes and without skeleton files in the server: - | username | - | brand-new-user | - And user "brand-new-user" has created folder "simple-folder" in the server - And user "brand-new-user" has created file "simple-folder/lorem.txt" in the server - And user "brand-new-user" has created file "lorem.txt" in the server - And user "brand-new-user" has logged in using the webUI - - @issue-ocis-1284 - Scenario Outline: deleting a file in a public share of a locked folder - Given user "brand-new-user" has locked folder "simple-folder" setting the following properties in the server - | lockscope | | - And user "brand-new-user" has created a public link with following settings in the server - | path | simple-folder | - | permissions | read, create, delete, update | - When the public uses the webUI to access the last public link created by user "brand-new-user" in a new session - And the user tries to delete folder "lorem.txt" using the webUI - Then notifications should be displayed on the webUI with the text - """ - Failed to delete "lorem.txt" - the file is locked - """ - When the user reloads the current page of the webUI - Then file "lorem.txt" should be listed on the webUI - Examples: - | lockscope | - | exclusive | - | shared | diff --git a/tests/acceptance/features/webUIWebdavLockProtection/move.feature b/tests/acceptance/features/webUIWebdavLockProtection/move.feature deleted file mode 100644 index 2429c58fc96..00000000000 --- a/tests/acceptance/features/webUIWebdavLockProtection/move.feature +++ /dev/null @@ -1,58 +0,0 @@ -Feature: Locks - As a user - I would like to be able to use locks control moving and renaming of files and folders - So that I can prevent files and folders being changed while they are being used by another user - - Background: - #do not set email, see bugs in https://github.com/owncloud/core/pull/32250#issuecomment-434615887 - Given these users have been created with default attributes and without skeleton files in the server: - | username | - | brand-new-user | - And user "brand-new-user" has created folder "simple-folder" in the server - And user "brand-new-user" has created folder "simple-empty-folder" in the server - And user "brand-new-user" has created file "simple-folder/lorem.txt" in the server - And user "brand-new-user" has created file "lorem.txt" in the server - And user "brand-new-user" has logged in using the webUI - - @issue-ocis-1284 - Scenario Outline: renaming a file in a public share of a locked folder - Given user "brand-new-user" has locked folder "simple-folder" setting the following properties in the server - | lockscope | | - And user "brand-new-user" has created a public link with following settings in the server - | path | simple-folder | - | permissions | read, create, delete, update | - When the public uses the webUI to access the last public link created by user "brand-new-user" in a new session - And the user tries to rename file "lorem.txt" to "a-renamed-file.txt" using the webUI - Then notifications should be displayed on the webUI with the text - """ - Failed to rename "lorem.txt" to "a-renamed-file.txt" - the file is locked - """ - When the user closes rename dialog - And the user reloads the current page of the webUI - Then file "lorem.txt" should be listed on the webUI - And file "a-renamed-file.txt" should not be listed on the webUI - Examples: - | lockscope | - | exclusive | - | shared | - - @issue-ocis-1284 - Scenario Outline: moving a locked file into an other folder in a public share - Given user "brand-new-user" has created folder "simple-folder/simple-empty-folder" in the server - And user "brand-new-user" has locked file "simple-folder/lorem.txt" setting the following properties in the server - | lockscope | | - And user "brand-new-user" has created a public link with following settings in the server - | path | simple-folder | - | permissions | read, create, delete, update | - When the public uses the webUI to access the last public link created by user "brand-new-user" in a new session - And the user tries to move file "lorem.txt" into folder "simple-empty-folder" using the webUI - Then notifications should be displayed on the webUI with the text - """ - Failed to move "lorem.txt" - """ - When the user navigates to the root of the last public link - Then file "lorem.txt" should be listed on the webUI - When the user opens folder "simple-empty-folder" using the webUI - Then file "lorem.txt" should not be listed on the webUI - Examples: - | lockscope | diff --git a/tests/acceptance/features/webUIWebdavLockProtection/upload.feature b/tests/acceptance/features/webUIWebdavLockProtection/upload.feature deleted file mode 100644 index cc22ed9fff7..00000000000 --- a/tests/acceptance/features/webUIWebdavLockProtection/upload.feature +++ /dev/null @@ -1,33 +0,0 @@ -Feature: Locks - As a user - I would like to be able to use locks control upload of files and folders - So that I can prevent files and folders being added to and changed while they are being used by another user - - Background: - #do not set email, see bugs in https://github.com/owncloud/core/pull/32250#issuecomment-434615887 - Given these users have been created with default attributes and without skeleton files in the server: - | username | - | brand-new-user | - And user "brand-new-user" has created folder "simple-folder" in the server - And user "brand-new-user" has uploaded file with content "file inside locked folder" to "simple-folder/lorem.txt" in the server - And user "brand-new-user" has uploaded file with content "locked file" to "lorem.txt" in the server - And user "brand-new-user" has logged in using the webUI - - @issue-5741 @issue-ocis-1284 - Scenario Outline: uploading a file, trying to overwrite a file in a locked folder in a public share - Given user "brand-new-user" has locked folder "simple-folder" setting the following properties in the server - | lockscope | | - And user "brand-new-user" has created a public link with following settings in the server - | path | simple-folder | - | permissions | read, create, delete, update | - When the public uses the webUI to access the last public link created by user "brand-new-user" in a new session - And the user uploads overwriting file "lorem.txt" using the webUI - Then notifications should be displayed on the webUI with the text - """ - The file lorem.txt is currently locked, please try again later - """ - And the content of file "simple-folder/lorem.txt" for user "brand-new-user" should be "file inside locked folder" in the server - Examples: - | lockscope | - | exclusive | - | shared | diff --git a/tests/e2e/cucumber/features/smoke/app-provider/lock.feature b/tests/e2e/cucumber/features/smoke/app-provider/lock.feature new file mode 100644 index 00000000000..f66540a7dce --- /dev/null +++ b/tests/e2e/cucumber/features/smoke/app-provider/lock.feature @@ -0,0 +1,50 @@ +Feature: lock + As a user + I can see that a file is locked if it is opened by a user with edit permissions, + and I am restricted in some actions such as moving deleting renaming a locked file + + + Scenario: file lock indication + Given "Admin" creates following users using API + | id | + | Alice | + | Brian | + | Carol | + And "Alice" logs in + And "Alice" creates the following files into personal space using API + | pathToFile | content | + | test.odt | some content | + And "Alice" creates the following folder in personal space using API + | name | + | folder | + And "Alice" shares the following resource using API + | resource | recipient | type | role | + | test.odt | Brian | user | Can edit | + + And "Brian" logs in + And "Brian" opens the "files" app + And "Brian" navigates to the shared with me page + When "Brian" opens the following file in Collabora + | resource | + | test.odt | + Then "Brian" should see the content "some content" in editor "Collabora" + + When "Alice" opens the "files" app + Then for "Alice" file "test.odt" should be locked + + # checking that sharing/unsharing and creating link of the locked file is possible + And "Alice" creates a public link creates a public link of following resource using the sidebar panel + | resource | password | + | test.odt | %public% | + And "Alice" shares the following resource using the sidebar panel + | resource | recipient | type | role | resourceType | + | test.odt | Carol | user | Can view | file | + # unsharing should remove lock https://github.com/owncloud/ocis/issues/8273 + # And "Alice" removes following sharee + # | resource | recipient | + # | test.odt | Brian | + And "Brian" logs out + + When "Alice" reloads the page + Then for "Alice" file "test.odt" should not be locked + And "Alice" logs out diff --git a/tests/e2e/cucumber/steps/ui/resources.ts b/tests/e2e/cucumber/steps/ui/resources.ts index ff5019fcccc..562bbd1f31c 100644 --- a/tests/e2e/cucumber/steps/ui/resources.ts +++ b/tests/e2e/cucumber/steps/ui/resources.ts @@ -493,7 +493,7 @@ When( ) When( - /^"([^"].*)" opens the following file(?:s)? in (mediaviewer|pdfviewer|texteditor)$/, + /^"([^"].*)" opens the following file(?:s)? in (mediaviewer|pdfviewer|texteditor|Collabora|OnlyOffice)$/, async function (this: World, stepUser: string, actionType: string, stepTable: DataTable) { const { page } = this.actorsEnvironment.getActor({ key: stepUser }) const resourceObject = new objects.applicationFiles.Resource({ page }) @@ -501,7 +501,12 @@ When( for (const info of stepTable.hashes()) { await resourceObject.openFileInViewer({ name: info.resource, - actionType: actionType as 'mediaviewer' | 'pdfviewer' | 'texteditor' + actionType: actionType as + | 'mediaviewer' + | 'pdfviewer' + | 'texteditor' + | 'Collabora' + | 'OnlyOffice' }) } } @@ -732,3 +737,16 @@ Then( await resourceObject.openShotcut({ name: name, url: url }) } ) + +Then( + /^for "([^"]*)" file "([^"]*)" (should|should not) be locked$/, + async function (this: World, stepUser: string, file: string, actionType: string) { + const { page } = this.actorsEnvironment.getActor({ key: stepUser }) + const resourceObject = new objects.applicationFiles.Resource({ page }) + const lockLocator = await resourceObject.getLockLocator({ resource: file }) + + actionType === 'should' + ? expect(lockLocator).toBeVisible() + : expect(lockLocator).not.toBeVisible() + } +) diff --git a/tests/e2e/support/objects/app-files/resource/actions.ts b/tests/e2e/support/objects/app-files/resource/actions.ts index df8a06616f9..187b405e511 100644 --- a/tests/e2e/support/objects/app-files/resource/actions.ts +++ b/tests/e2e/support/objects/app-files/resource/actions.ts @@ -1,4 +1,4 @@ -import { Download, Page, expect } from '@playwright/test' +import { Download, Locator, Page, expect } from '@playwright/test' import util from 'util' import path from 'path' import { resourceExists, waitForResources } from './utils' @@ -111,6 +111,8 @@ const textEditorTextArea = '#text-editor-input' const filesContextMenuAction = 'div[id^="context-menu-drop"] button.oc-files-actions-%s-trigger' const highlightedFileRowSelector = '#files-space-table tr.oc-table-highlighted' const emptyTrashbinButtonSelector = '.oc-files-actions-empty-trash-bin-trigger' +const resourceLockIcon = + '//*[@data-test-resource-name="%s"]/ancestor::tr//td//span[contains(@class, "oc-resource-icon-status-badge-inner")]' export const clickResource = async ({ page, @@ -555,12 +557,12 @@ export const startResourceUpload = (args: uploadResourceArgs): Promise => return performUpload(args) } -const puaseResumeUpload = (page: Page): Promise => { +const pauseResumeUpload = (page: Page): Promise => { return page.locator(pauseResumeUploadButton).click() } export const pauseResourceUpload = async (page: Page): Promise => { - await puaseResumeUpload(page) + await pauseResumeUpload(page) await Promise.all([ page.locator(uploadResumeTooltip).waitFor(), page.locator(pauseResumeUploadButton).hover() @@ -568,7 +570,7 @@ export const pauseResourceUpload = async (page: Page): Promise => { } export const resumeResourceUpload = async (page: Page): Promise => { - await puaseResumeUpload(page) + await pauseResumeUpload(page) await Promise.all([ page.locator(uploadPauseTooltip).waitFor(), page.locator(pauseResumeUploadButton).hover() @@ -1449,32 +1451,50 @@ export const removeTagsFromResource = async (args: resourceTagsArgs): Promise => { const { page, name, actionType } = args - if (actionType === 'mediaviewer') { - await Promise.all([ - page.waitForResponse( - (resp) => - resp.url().includes('preview') && - resp.status() === 200 && - resp.request().method() === 'GET' - ), - page.locator(util.format(resourceNameSelector, name)).click() - ]) + switch (actionType) { + case 'OnlyOffice': + case 'Collabora': + await Promise.all([ + page.waitForResponse( + (resp) => + resp.url().includes(`app_name=${actionType}`) && + resp.status() === 200 && + resp.request().method() === 'POST' + ), + page.locator(util.format(resourceNameSelector, name)).click() + ]) + break + case 'mediaviewer': { + await Promise.all([ + page.waitForResponse( + (resp) => + resp.url().includes('preview') && + resp.status() === 200 && + resp.request().method() === 'GET' + ), + page.locator(util.format(resourceNameSelector, name)).click() + ]) - // in case of error doesn't contain src="blob:https://url" - expect(await page.locator(previewImage).getAttribute('src')).toContain('blob') - } else { - await Promise.all([ - page.waitForResponse( - (resp) => resp.status() === 207 && resp.request().method() === 'PROPFIND' - ), - page.locator(util.format(resourceNameSelector, name)).click() - ]) + // in case of error doesn't contain src="blob:https://url" + expect(await page.locator(previewImage).getAttribute('src')).toContain('blob') + break + } + case 'pdfviewer': + case 'texteditor': { + await Promise.all([ + page.waitForResponse( + (resp) => resp.status() === 207 && resp.request().method() === 'PROPFIND' + ), + page.locator(util.format(resourceNameSelector, name)).click() + ]) + break + } } } @@ -1640,3 +1660,13 @@ export const openShotcut = async ({ ]) } } + +export interface expectFileToBeLockedArgs { + page: Page + resource: string +} + +export const getLockLocator = async (args: expectFileToBeLockedArgs): Promise => { + const { page, resource } = args + return await page.locator(util.format(resourceLockIcon, resource)) +} diff --git a/tests/e2e/support/objects/app-files/resource/index.ts b/tests/e2e/support/objects/app-files/resource/index.ts index 30a640ee6fa..d302e4b0bf1 100644 --- a/tests/e2e/support/objects/app-files/resource/index.ts +++ b/tests/e2e/support/objects/app-files/resource/index.ts @@ -1,4 +1,4 @@ -import { Download, Page } from '@playwright/test' +import { Download, Locator, Page } from '@playwright/test' import * as po from './actions' import { Space } from '../../../types' @@ -281,4 +281,8 @@ export class Resource { async openShotcut({ name, url }: { name: string; url?: string }): Promise { await po.openShotcut({ page: this.#page, name: name, url: url }) } + + async getLockLocator(args: Omit): Promise { + return po.getLockLocator({ ...args, page: this.#page }) + } }