summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorMorris Jobke <hey@morrisjobke.de>2018-03-09 11:12:04 +0100
committerGitHub <noreply@github.com>2018-03-09 11:12:04 +0100
commit5924f9cb3089d76bf33e5d497ed79e2af9b28e7a (patch)
tree34f587ae3c885a25f1030ec60edb02912412e3a7 /tests
parented5008597f43a28114b04dfe4706cf5d6a6b5e57 (diff)
parent15c12eb0270a35fa875e519b04d8378afc6e795d (diff)
downloadnextcloud-server-5924f9cb3089d76bf33e5d497ed79e2af9b28e7a.tar.gz
nextcloud-server-5924f9cb3089d76bf33e5d497ed79e2af9b28e7a.zip
Merge pull request #8594 from nextcloud/add-acceptance-tests-for-permissions-on-public-shared-folders
Add acceptance tests for permissions on public shared folders
Diffstat (limited to 'tests')
-rw-r--r--tests/acceptance/config/behat.yml1
-rw-r--r--tests/acceptance/features/app-files.feature65
-rw-r--r--tests/acceptance/features/bootstrap/FileListAncestorSetter.php67
-rw-r--r--tests/acceptance/features/bootstrap/FileListContext.php374
-rw-r--r--tests/acceptance/features/bootstrap/FilesAppContext.php309
-rw-r--r--tests/acceptance/features/bootstrap/FilesSharingAppContext.php21
-rw-r--r--tests/acceptance/features/bootstrap/WaitFor.php78
-rw-r--r--tests/acceptance/features/core/Actor.php18
-rw-r--r--tests/acceptance/features/core/ActorContext.php4
9 files changed, 638 insertions, 299 deletions
diff --git a/tests/acceptance/config/behat.yml b/tests/acceptance/config/behat.yml
index 3495769457d..ba41618b895 100644
--- a/tests/acceptance/config/behat.yml
+++ b/tests/acceptance/config/behat.yml
@@ -12,6 +12,7 @@ default:
- AppNavigationContext
- CommentsAppContext
- FeatureContext
+ - FileListContext
- FilesAppContext
- FilesSharingAppContext
- LoginPageContext
diff --git a/tests/acceptance/features/app-files.feature b/tests/acceptance/features/app-files.feature
index dd5340d6374..97f17344187 100644
--- a/tests/acceptance/features/app-files.feature
+++ b/tests/acceptance/features/app-files.feature
@@ -41,6 +41,71 @@ Feature: app-files
And I open the Share menu
Then I see that the Share menu is shown
+ Scenario: creation is not possible by default in a public shared folder
+ Given I act as John
+ And I am logged in
+ And I create a new folder named "Shared folder"
+ # To share the link the "Share" inline action has to be clicked but, as the
+ # details view is opened automatically when the folder is created, clicking
+ # on the inline action could fail if it is covered by the details view due
+ # to its opening animation. Instead of ensuring that the animations of the
+ # contents and the details view have both finished it is easier to close the
+ # details view and wait until it is closed before continuing.
+ And I close the details view
+ And I see that the details view is closed
+ And I share the link for "Shared folder"
+ And I write down the shared link
+ When I act as Jane
+ And I visit the shared link I wrote down
+ And I see that the current page is the shared link I wrote down
+ And I see that the file list is eventually loaded
+ Then I see that it is not possible to create new files
+
+ Scenario: create folder in a public editable shared folder
+ Given I act as John
+ And I am logged in
+ And I create a new folder named "Editable shared folder"
+ # To share the link the "Share" inline action has to be clicked but, as the
+ # details view is opened automatically when the folder is created, clicking
+ # on the inline action could fail if it is covered by the details view due
+ # to its opening animation. Instead of ensuring that the animations of the
+ # contents and the details view have both finished it is easier to close the
+ # details view and wait until it is closed before continuing.
+ And I close the details view
+ And I see that the details view is closed
+ And I share the link for "Editable shared folder"
+ And I set the shared link as editable
+ And I write down the shared link
+ When I act as Jane
+ And I visit the shared link I wrote down
+ And I see that the current page is the shared link I wrote down
+ And I create a new folder named "Subfolder"
+ Then I see that the file list contains a file named "Subfolder"
+
+ Scenario: owner sees folder created in the public page of an editable shared folder
+ Given I act as John
+ And I am logged in
+ And I create a new folder named "Editable shared folder"
+ # To share the link the "Share" inline action has to be clicked but, as the
+ # details view is opened automatically when the folder is created, clicking
+ # on the inline action could fail if it is covered by the details view due
+ # to its opening animation. Instead of ensuring that the animations of the
+ # contents and the details view have both finished it is easier to close the
+ # details view and wait until it is closed before continuing.
+ And I close the details view
+ And I see that the details view is closed
+ And I share the link for "Editable shared folder"
+ And I set the shared link as editable
+ And I write down the shared link
+ And I act as Jane
+ And I visit the shared link I wrote down
+ And I see that the current page is the shared link I wrote down
+ And I create a new folder named "Subfolder"
+ And I see that the file list contains a file named "Subfolder"
+ When I act as John
+ And I enter in the folder named "Editable shared folder"
+ Then I see that the file list contains a file named "Subfolder"
+
Scenario: set a password to a shared link
Given I am logged in
And I share the link for "welcome.txt"
diff --git a/tests/acceptance/features/bootstrap/FileListAncestorSetter.php b/tests/acceptance/features/bootstrap/FileListAncestorSetter.php
new file mode 100644
index 00000000000..2f8d3ad00e5
--- /dev/null
+++ b/tests/acceptance/features/bootstrap/FileListAncestorSetter.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ *
+ * @copyright Copyright (c) 2018, Daniel Calviño Sánchez (danxuliu@gmail.com)
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+use Behat\Behat\Context\Context;
+use Behat\Behat\Hook\Scope\BeforeScenarioScope;
+
+/**
+ * Helper trait to set the ancestor of the file list.
+ *
+ * The FileListContext provides steps to interact with and check the behaviour
+ * of a file list. However, the FileListContext does not know the right file
+ * list ancestor that has to be used by the file list steps; this has to be set
+ * from other contexts, for example, when the Files app or the public page for a
+ * shared folder is opened.
+ *
+ * Contexts that "know" that certain file list ancestor has to be used by the
+ * FileListContext steps should use this trait and call
+ * "setFileListAncestorForActor" when needed.
+ */
+trait FileListAncestorSetter {
+
+ /**
+ * @var FileListContext
+ */
+ private $fileListContext;
+
+ /**
+ * @BeforeScenario
+ */
+ public function getSiblingFileListContext(BeforeScenarioScope $scope) {
+ $environment = $scope->getEnvironment();
+
+ $this->fileListContext = $environment->getContext("FileListContext");
+ }
+
+ /**
+ * Sets the file list ancestor to be used in the file list steps performed
+ * by the given actor.
+ *
+ * @param null|Locator $fileListAncestor the file list ancestor
+ * @param Actor $actor the actor
+ */
+ private function setFileListAncestorForActor($fileListAncestor, Actor $actor) {
+ $this->fileListContext->setFileListAncestorForActor($fileListAncestor, $actor);
+ }
+
+}
diff --git a/tests/acceptance/features/bootstrap/FileListContext.php b/tests/acceptance/features/bootstrap/FileListContext.php
new file mode 100644
index 00000000000..bc225e3f9b1
--- /dev/null
+++ b/tests/acceptance/features/bootstrap/FileListContext.php
@@ -0,0 +1,374 @@
+<?php
+
+/**
+ *
+ * @copyright Copyright (c) 2018, Daniel Calviño Sánchez (danxuliu@gmail.com)
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+use Behat\Behat\Context\Context;
+
+class FileListContext implements Context, ActorAwareInterface {
+
+ /**
+ * @var Actor
+ */
+ private $actor;
+
+ /**
+ * @var array
+ */
+ private $fileListAncestorsByActor;
+
+ /**
+ * @var Locator
+ */
+ private $fileListAncestor;
+
+ /**
+ * @BeforeScenario
+ */
+ public function initializeFileListAncestors() {
+ $this->fileListAncestorsByActor = array();
+ $this->fileListAncestor = null;
+ }
+
+ /**
+ * @param Actor $actor
+ */
+ public function setCurrentActor(Actor $actor) {
+ $this->actor = $actor;
+
+ if (array_key_exists($actor->getName(), $this->fileListAncestorsByActor)) {
+ $this->fileListAncestor = $this->fileListAncestorsByActor[$actor->getName()];
+ } else {
+ $this->fileListAncestor = null;
+ }
+ }
+
+ /**
+ * Sets the file list ancestor to be used in the steps performed by the
+ * given actor from that point on (until changed again).
+ *
+ * This is meant to be called from other contexts, for example, when the
+ * Files app or the public page for a shared folder are opened.
+ *
+ * The FileListAncestorSetter trait can be used to reduce the boilerplate
+ * needed to set the file list ancestor from other contexts.
+ *
+ * @param null|Locator $fileListAncestor the file list ancestor
+ * @param Actor $actor the actor
+ */
+ public function setFileListAncestorForActor($fileListAncestor, Actor $actor) {
+ $this->fileListAncestorsByActor[$actor->getName()] = $fileListAncestor;
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function mainWorkingIcon($fileListAncestor) {
+ return Locator::forThe()->css(".mask.icon-loading")->
+ descendantOf($fileListAncestor)->
+ describedAs("Main working icon in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function createMenuButton($fileListAncestor) {
+ return Locator::forThe()->css("#controls .button.new")->
+ descendantOf($fileListAncestor)->
+ describedAs("Create menu button in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ private static function createMenuItemFor($fileListAncestor, $newType) {
+ return Locator::forThe()->xpath("//div[contains(concat(' ', normalize-space(@class), ' '), ' newFileMenu ')]//span[normalize-space() = '$newType']/ancestor::li")->
+ descendantOf($fileListAncestor)->
+ describedAs("Create $newType menu item in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function createNewFolderMenuItem($fileListAncestor) {
+ return self::createMenuItemFor($fileListAncestor, "New folder");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function createNewFolderMenuItemNameInput($fileListAncestor) {
+ return Locator::forThe()->css(".filenameform input")->
+ descendantOf(self::createNewFolderMenuItem($fileListAncestor))->
+ describedAs("Name input in create new folder menu item in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function rowForFile($fileListAncestor, $fileName) {
+ return Locator::forThe()->xpath("//*[@id = 'fileList']//span[contains(concat(' ', normalize-space(@class), ' '), ' nametext ') and normalize-space() = '$fileName']/ancestor::tr")->
+ descendantOf($fileListAncestor)->
+ describedAs("Row for file $fileName in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function rowForFilePreceding($fileListAncestor, $fileName1, $fileName2) {
+ return Locator::forThe()->xpath("//preceding-sibling::tr//span[contains(concat(' ', normalize-space(@class), ' '), ' nametext ') and normalize-space() = '$fileName1']/ancestor::tr")->
+ descendantOf(self::rowForFile($fileListAncestor, $fileName2))->
+ describedAs("Row for file $fileName1 preceding $fileName2 in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function favoriteMarkForFile($fileListAncestor, $fileName) {
+ return Locator::forThe()->css(".favorite-mark")->
+ descendantOf(self::rowForFile($fileListAncestor, $fileName))->
+ describedAs("Favorite mark for file $fileName in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function notFavoritedStateIconForFile($fileListAncestor, $fileName) {
+ return Locator::forThe()->css(".icon-star")->
+ descendantOf(self::favoriteMarkForFile($fileListAncestor, $fileName))->
+ describedAs("Not favorited state icon for file $fileName in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function favoritedStateIconForFile($fileListAncestor, $fileName) {
+ return Locator::forThe()->css(".icon-starred")->
+ descendantOf(self::favoriteMarkForFile($fileListAncestor, $fileName))->
+ describedAs("Favorited state icon for file $fileName in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function mainLinkForFile($fileListAncestor, $fileName) {
+ return Locator::forThe()->css(".name")->
+ descendantOf(self::rowForFile($fileListAncestor, $fileName))->
+ describedAs("Main link for file $fileName in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function renameInputForFile($fileListAncestor, $fileName) {
+ return Locator::forThe()->css("input.filename")->
+ descendantOf(self::rowForFile($fileListAncestor, $fileName))->
+ describedAs("Rename input for file $fileName in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function shareActionForFile($fileListAncestor, $fileName) {
+ return Locator::forThe()->css(".action-share")->
+ descendantOf(self::rowForFile($fileListAncestor, $fileName))->
+ describedAs("Share action for file $fileName in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function fileActionsMenuButtonForFile($fileListAncestor, $fileName) {
+ return Locator::forThe()->css(".action-menu")->
+ descendantOf(self::rowForFile($fileListAncestor, $fileName))->
+ describedAs("File actions menu button for file $fileName in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function fileActionsMenu() {
+ return Locator::forThe()->css(".fileActionsMenu")->
+ describedAs("File actions menu in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ private static function fileActionsMenuItemFor($itemText) {
+ return Locator::forThe()->xpath("//a[normalize-space() = '$itemText']")->
+ descendantOf(self::fileActionsMenu())->
+ describedAs($itemText . " item in file actions menu in file list");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function addToFavoritesMenuItem() {
+ return self::fileActionsMenuItemFor("Add to favorites");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function removeFromFavoritesMenuItem() {
+ return self::fileActionsMenuItemFor("Remove from favorites");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function detailsMenuItem() {
+ return self::fileActionsMenuItemFor("Details");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function renameMenuItem() {
+ return self::fileActionsMenuItemFor("Rename");
+ }
+
+ /**
+ * @return Locator
+ */
+ public static function viewFileInFolderMenuItem() {
+ return self::fileActionsMenuItemFor("View in folder");
+ }
+
+ /**
+ * @Given I create a new folder named :folderName
+ */
+ public function iCreateANewFolderNamed($folderName) {
+ $this->actor->find(self::createMenuButton($this->fileListAncestor), 10)->click();
+
+ $this->actor->find(self::createNewFolderMenuItem($this->fileListAncestor), 2)->click();
+ $this->actor->find(self::createNewFolderMenuItemNameInput($this->fileListAncestor), 2)->setValue($folderName . "\r");
+ }
+
+ /**
+ * @Given I enter in the folder named :folderName
+ */
+ public function iEnterInTheFolderNamed($folderName) {
+ $this->actor->find(self::mainLinkForFile($this->fileListAncestor, $folderName), 10)->click();
+ }
+
+ /**
+ * @Given I open the details view for :fileName
+ */
+ public function iOpenTheDetailsViewFor($fileName) {
+ $this->actor->find(self::fileActionsMenuButtonForFile($this->fileListAncestor, $fileName), 10)->click();
+
+ $this->actor->find(self::detailsMenuItem(), 2)->click();
+ }
+
+ /**
+ * @Given I rename :fileName1 to :fileName2
+ */
+ public function iRenameTo($fileName1, $fileName2) {
+ $this->actor->find(self::fileActionsMenuButtonForFile($this->fileListAncestor, $fileName1), 10)->click();
+
+ $this->actor->find(self::renameMenuItem(), 2)->click();
+
+ $this->actor->find(self::renameInputForFile($this->fileListAncestor, $fileName1), 10)->setValue($fileName2 . "\r");
+ }
+
+ /**
+ * @Given I mark :fileName as favorite
+ */
+ public function iMarkAsFavorite($fileName) {
+ $this->iSeeThatIsNotMarkedAsFavorite($fileName);
+
+ $this->actor->find(self::fileActionsMenuButtonForFile($this->fileListAncestor, $fileName), 10)->click();
+
+ $this->actor->find(self::addToFavoritesMenuItem(), 2)->click();
+ }
+
+ /**
+ * @Given I unmark :fileName as favorite
+ */
+ public function iUnmarkAsFavorite($fileName) {
+ $this->iSeeThatIsMarkedAsFavorite($fileName);
+
+ $this->actor->find(self::fileActionsMenuButtonForFile($this->fileListAncestor, $fileName), 10)->click();
+
+ $this->actor->find(self::removeFromFavoritesMenuItem(), 2)->click();
+ }
+
+ /**
+ * @When I view :fileName in folder
+ */
+ public function iViewInFolder($fileName) {
+ $this->actor->find(self::fileActionsMenuButtonForFile($this->fileListAncestor, $fileName), 10)->click();
+
+ $this->actor->find(self::viewFileInFolderMenuItem(), 2)->click();
+ }
+
+ /**
+ * @Then I see that the file list is eventually loaded
+ */
+ public function iSeeThatTheFileListIsEventuallyLoaded() {
+ if (!WaitFor::elementToBeEventuallyNotShown(
+ $this->actor,
+ self::mainWorkingIcon($this->fileListAncestor),
+ $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
+ PHPUnit_Framework_Assert::fail("The main working icon for the file list is still shown after $timeout seconds");
+ }
+ }
+
+ /**
+ * @Then I see that it is not possible to create new files
+ */
+ public function iSeeThatItIsNotPossibleToCreateNewFiles() {
+ // Once a file list is loaded the "Create" menu button is always in the
+ // DOM, so it is checked if it is visible or not.
+ PHPUnit_Framework_Assert::assertFalse($this->actor->find(self::createMenuButton($this->fileListAncestor))->isVisible());
+ }
+
+ /**
+ * @Then I see that the file list contains a file named :fileName
+ */
+ public function iSeeThatTheFileListContainsAFileNamed($fileName) {
+ PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::rowForFile($this->fileListAncestor, $fileName), 10));
+ }
+
+ /**
+ * @Then I see that :fileName1 precedes :fileName2 in the file list
+ */
+ public function iSeeThatPrecedesInTheFileList($fileName1, $fileName2) {
+ PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::rowForFilePreceding($this->fileListAncestor, $fileName1, $fileName2), 10));
+ }
+
+ /**
+ * @Then I see that :fileName is marked as favorite
+ */
+ public function iSeeThatIsMarkedAsFavorite($fileName) {
+ PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::favoritedStateIconForFile($this->fileListAncestor, $fileName), 10));
+ }
+
+ /**
+ * @Then I see that :fileName is not marked as favorite
+ */
+ public function iSeeThatIsNotMarkedAsFavorite($fileName) {
+ PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::notFavoritedStateIconForFile($this->fileListAncestor, $fileName), 10));
+ }
+
+}
diff --git a/tests/acceptance/features/bootstrap/FilesAppContext.php b/tests/acceptance/features/bootstrap/FilesAppContext.php
index 117f3b54fb8..50997d98b0f 100644
--- a/tests/acceptance/features/bootstrap/FilesAppContext.php
+++ b/tests/acceptance/features/bootstrap/FilesAppContext.php
@@ -26,6 +26,7 @@ use Behat\Behat\Context\Context;
class FilesAppContext implements Context, ActorAwareInterface {
use ActorAware;
+ use FileListAncestorSetter;
/**
* @return array
@@ -216,6 +217,18 @@ class FilesAppContext implements Context, ActorAwareInterface {
/**
* @return Locator
*/
+ public static function allowUploadAndEditingRadioButton() {
+ // forThe()->radio("Allow upload and editing") can not be used here;
+ // that would return the radio button itself, but the element that the
+ // user interacts with is the label.
+ return Locator::forThe()->xpath("//label[normalize-space() = 'Allow upload and editing']")->
+ descendantOf(self::currentSectionDetailsView())->
+ describedAs("Allow upload and editing radio button in the details view in Files app");
+ }
+
+ /**
+ * @return Locator
+ */
public static function passwordProtectCheckbox() {
// forThe()->checkbox("Password protect") can not be used here; that
// would return the checkbox itself, but the element that the user
@@ -242,185 +255,6 @@ class FilesAppContext implements Context, ActorAwareInterface {
}
/**
- * @return Locator
- */
- public static function createMenuButton() {
- return Locator::forThe()->css("#controls .button.new")->
- descendantOf(self::currentSectionMainView())->
- describedAs("Create menu button in Files app");
- }
-
- /**
- * @return Locator
- */
- public static function createNewFolderMenuItem() {
- return self::createMenuItemFor("New folder");
- }
-
- /**
- * @return Locator
- */
- public static function createNewFolderMenuItemNameInput() {
- return Locator::forThe()->css(".filenameform input")->
- descendantOf(self::createNewFolderMenuItem())->
- describedAs("Name input in create new folder menu item in Files app");
- }
-
- /**
- * @return Locator
- */
- private static function createMenuItemFor($newType) {
- return Locator::forThe()->xpath("//div[contains(concat(' ', normalize-space(@class), ' '), ' newFileMenu ')]//span[normalize-space() = '$newType']/ancestor::li")->
- descendantOf(self::currentSectionMainView())->
- describedAs("Create $newType menu item in Files app");
- }
-
- /**
- * @return Locator
- */
- public static function rowForFile($fileName) {
- return Locator::forThe()->xpath("//*[@id = 'fileList']//span[contains(concat(' ', normalize-space(@class), ' '), ' nametext ') and normalize-space() = '$fileName']/ancestor::tr")->
- descendantOf(self::currentSectionMainView())->
- describedAs("Row for file $fileName in Files app");
- }
-
- /**
- * @return Locator
- */
- public static function rowForFilePreceding($fileName1, $fileName2) {
- return Locator::forThe()->xpath("//preceding-sibling::tr//span[contains(concat(' ', normalize-space(@class), ' '), ' nametext ') and normalize-space() = '$fileName1']/ancestor::tr")->
- descendantOf(self::rowForFile($fileName2))->
- describedAs("Row for file $fileName1 preceding $fileName2 in Files app");
- }
-
- /**
- * @return Locator
- */
- public static function favoriteMarkForFile($fileName) {
- return Locator::forThe()->css(".favorite-mark")->descendantOf(self::rowForFile($fileName))->
- describedAs("Favorite mark for file $fileName in Files app");
- }
-
- /**
- * @return Locator
- */
- public static function notFavoritedStateIconForFile($fileName) {
- return Locator::forThe()->css(".icon-star")->descendantOf(self::favoriteMarkForFile($fileName))->
- describedAs("Not favorited state icon for file $fileName in Files app");
- }
-
- /**
- * @return Locator
- */
- public static function favoritedStateIconForFile($fileName) {
- return Locator::forThe()->css(".icon-starred")->descendantOf(self::favoriteMarkForFile($fileName))->
- describedAs("Favorited state icon for file $fileName in Files app");
- }
-
- /**
- * @return Locator
- */
- public static function mainLinkForFile($fileName) {
- return Locator::forThe()->css(".name")->descendantOf(self::rowForFile($fileName))->
- describedAs("Main link for file $fileName in Files app");
- }
-
- /**
- * @return Locator
- */
- public static function renameInputForFile($fileName) {
- return Locator::forThe()->css("input.filename")->descendantOf(self::rowForFile($fileName))->
- describedAs("Rename input for file $fileName in Files app");
- }
-
- /**
- * @return Locator
- */
- public static function shareActionForFile($fileName) {
- return Locator::forThe()->css(".action-share")->descendantOf(self::rowForFile($fileName))->
- describedAs("Share action for file $fileName in Files app");
- }
-
- /**
- * @return Locator
- */
- public static function fileActionsMenuButtonForFile($fileName) {
- return Locator::forThe()->css(".action-menu")->descendantOf(self::rowForFile($fileName))->
- describedAs("File actions menu button for file $fileName in Files app");
- }
-
- /**
- * @return Locator
- */
- public static function fileActionsMenu() {
- return Locator::forThe()->css(".fileActionsMenu")->
- describedAs("File actions menu in Files app");
- }
-
- /**
- * @return Locator
- */
- public static function detailsMenuItem() {
- return self::fileActionsMenuItemFor("Details");
- }
-
- /**
- * @return Locator
- */
- public static function renameMenuItem() {
- return self::fileActionsMenuItemFor("Rename");
- }
-
- /**
- * @return Locator
- */
- public static function addToFavoritesMenuItem() {
- return self::fileActionsMenuItemFor("Add to favorites");
- }
-
- /**
- * @return Locator
- */
- public static function removeFromFavoritesMenuItem() {
- return self::fileActionsMenuItemFor("Remove from favorites");
- }
-
- /**
- * @return Locator
- */
- public static function viewFileInFolderMenuItem() {
- return self::fileActionsMenuItemFor("View in folder");
- }
-
- /**
- * @return Locator
- */
- private static function fileActionsMenuItemFor($itemText) {
- return Locator::forThe()->xpath("//a[normalize-space() = '$itemText']")->
- descendantOf(self::fileActionsMenu())->
- describedAs($itemText . " item in file actions menu in Files app");
- }
-
- /**
- * @Given I create a new folder named :folderName
- */
- public function iCreateANewFolderNamed($folderName) {
- $this->actor->find(self::createMenuButton(), 10)->click();
-
- $this->actor->find(self::createNewFolderMenuItem(), 2)->click();
- $this->actor->find(self::createNewFolderMenuItemNameInput(), 2)->setValue($folderName . "\r");
- }
-
- /**
- * @Given I open the details view for :fileName
- */
- public function iOpenTheDetailsViewFor($fileName) {
- $this->actor->find(self::fileActionsMenuButtonForFile($fileName), 10)->click();
-
- $this->actor->find(self::detailsMenuItem(), 2)->click();
- }
-
- /**
* @Given I close the details view
*/
public function iCloseTheDetailsView() {
@@ -442,43 +276,10 @@ class FilesAppContext implements Context, ActorAwareInterface {
}
/**
- * @Given I rename :fileName1 to :fileName2
- */
- public function iRenameTo($fileName1, $fileName2) {
- $this->actor->find(self::fileActionsMenuButtonForFile($fileName1), 10)->click();
-
- $this->actor->find(self::renameMenuItem(), 2)->click();
-
- $this->actor->find(self::renameInputForFile($fileName1), 10)->setValue($fileName2 . "\r");
- }
-
- /**
- * @Given I mark :fileName as favorite
- */
- public function iMarkAsFavorite($fileName) {
- $this->iSeeThatIsNotMarkedAsFavorite($fileName);
-
- $this->actor->find(self::fileActionsMenuButtonForFile($fileName), 10)->click();
-
- $this->actor->find(self::addToFavoritesMenuItem(), 2)->click();
- }
-
- /**
- * @Given I unmark :fileName as favorite
- */
- public function iUnmarkAsFavorite($fileName) {
- $this->iSeeThatIsMarkedAsFavorite($fileName);
-
- $this->actor->find(self::fileActionsMenuButtonForFile($fileName), 10)->click();
-
- $this->actor->find(self::removeFromFavoritesMenuItem(), 2)->click();
- }
-
- /**
* @Given I share the link for :fileName
*/
public function iShareTheLinkFor($fileName) {
- $this->actor->find(self::shareActionForFile($fileName), 10)->click();
+ $this->actor->find(FileListContext::shareActionForFile(self::currentSectionMainView(), $fileName), 10)->click();
$this->actor->find(self::shareLinkCheckbox(), 5)->click();
}
@@ -490,7 +291,8 @@ class FilesAppContext implements Context, ActorAwareInterface {
// The shared link field always exists in the DOM (once the "Sharing"
// tab is loaded), but its value is the actual shared link only when it
// is visible.
- if (!$this->waitForElementToBeEventuallyShown(
+ if (!WaitFor::elementToBeEventuallyShown(
+ $this->actor,
self::shareLinkField(),
$timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
PHPUnit_Framework_Assert::fail("The shared link was not shown yet after $timeout seconds");
@@ -500,15 +302,6 @@ class FilesAppContext implements Context, ActorAwareInterface {
}
/**
- * @When I view :fileName in folder
- */
- public function iViewInFolder($fileName) {
- $this->actor->find(self::fileActionsMenuButtonForFile($fileName), 10)->click();
-
- $this->actor->find(self::viewFileInFolderMenuItem(), 2)->click();
- }
-
- /**
* @When I check the tag :tag in the dropdown for tags in the details view
*/
public function iCheckTheTagInTheDropdownForTagsInTheDetailsView($tag) {
@@ -527,6 +320,13 @@ class FilesAppContext implements Context, ActorAwareInterface {
}
/**
+ * @When I set the shared link as editable
+ */
+ public function iSetTheSharedLinkAsEditable() {
+ $this->actor->find(self::allowUploadAndEditingRadioButton(), 10)->click();
+ }
+
+ /**
* @When I protect the shared link with the password :password
*/
public function iProtectTheSharedLinkWithThePassword($password) {
@@ -542,6 +342,8 @@ class FilesAppContext implements Context, ActorAwareInterface {
PHPUnit_Framework_Assert::assertStringStartsWith(
$this->actor->locatePath("/apps/files/"),
$this->actor->getSession()->getCurrentUrl());
+
+ $this->setFileListAncestorForActor(self::currentSectionMainView(), $this->actor);
}
/**
@@ -578,34 +380,6 @@ class FilesAppContext implements Context, ActorAwareInterface {
}
/**
- * @Then I see that the file list contains a file named :fileName
- */
- public function iSeeThatTheFileListContainsAFileNamed($fileName) {
- PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::rowForFile($fileName), 10));
- }
-
- /**
- * @Then I see that :fileName1 precedes :fileName2 in the file list
- */
- public function iSeeThatPrecedesInTheFileList($fileName1, $fileName2) {
- PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::rowForFilePreceding($fileName1, $fileName2), 10));
- }
-
- /**
- * @Then I see that :fileName is marked as favorite
- */
- public function iSeeThatIsMarkedAsFavorite($fileName) {
- PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::favoritedStateIconForFile($fileName), 10));
- }
-
- /**
- * @Then I see that :fileName is not marked as favorite
- */
- public function iSeeThatIsNotMarkedAsFavorite($fileName) {
- PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::notFavoritedStateIconForFile($fileName), 10));
- }
-
- /**
* @Then I see that the file name shown in the details view is :fileName
*/
public function iSeeThatTheFileNameShownInTheDetailsViewIs($fileName) {
@@ -665,7 +439,8 @@ class FilesAppContext implements Context, ActorAwareInterface {
* @When I see that the :tabName tab in the details view is eventually loaded
*/
public function iSeeThatTheTabInTheDetailsViewIsEventuallyLoaded($tabName) {
- if (!$this->waitForElementToBeEventuallyNotShown(
+ if (!WaitFor::elementToBeEventuallyNotShown(
+ $this->actor,
self::loadingIconForTabInCurrentSectionDetailsViewNamed($tabName),
$timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
PHPUnit_Framework_Assert::fail("The $tabName tab in the details view has not been loaded after $timeout seconds");
@@ -683,7 +458,8 @@ class FilesAppContext implements Context, ActorAwareInterface {
* @Then I see that the working icon for password protect is eventually not shown
*/
public function iSeeThatTheWorkingIconForPasswordProtectIsEventuallyNotShown() {
- if (!$this->waitForElementToBeEventuallyNotShown(
+ if (!WaitFor::elementToBeEventuallyNotShown(
+ $this->actor,
self::passwordProtectWorkingIcon(),
$timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
PHPUnit_Framework_Assert::fail("The working icon for password protect is still shown after $timeout seconds");
@@ -700,31 +476,4 @@ class FilesAppContext implements Context, ActorAwareInterface {
$this->iSeeThatTheWorkingIconForPasswordProtectIsEventuallyNotShown();
}
- private function waitForElementToBeEventuallyShown($elementLocator, $timeout = 10, $timeoutStep = 1) {
- $actor = $this->actor;
-
- $elementShownCallback = function() use ($actor, $elementLocator) {
- try {
- return $actor->find($elementLocator)->isVisible();
- } catch (NoSuchElementException $exception) {
- return false;
- }
- };
-
- return Utils::waitFor($elementShownCallback, $timeout, $timeoutStep);
- }
-
- private function waitForElementToBeEventuallyNotShown($elementLocator, $timeout = 10, $timeoutStep = 1) {
- $actor = $this->actor;
-
- $elementNotShownCallback = function() use ($actor, $elementLocator) {
- try {
- return !$actor->find($elementLocator)->isVisible();
- } catch (NoSuchElementException $exception) {
- return true;
- }
- };
-
- return Utils::waitFor($elementNotShownCallback, $timeout, $timeoutStep);
- }
}
diff --git a/tests/acceptance/features/bootstrap/FilesSharingAppContext.php b/tests/acceptance/features/bootstrap/FilesSharingAppContext.php
index 4b7dd08c83e..4f9dabc60e6 100644
--- a/tests/acceptance/features/bootstrap/FilesSharingAppContext.php
+++ b/tests/acceptance/features/bootstrap/FilesSharingAppContext.php
@@ -26,6 +26,7 @@ use Behat\Behat\Context\Context;
class FilesSharingAppContext implements Context, ActorAwareInterface {
use ActorAware;
+ use FileListAncestorSetter;
/**
* @return Locator
@@ -156,6 +157,8 @@ class FilesSharingAppContext implements Context, ActorAwareInterface {
PHPUnit_Framework_Assert::assertEquals(
$this->actor->getSharedNotebook()["shared link"],
$this->actor->getSession()->getCurrentUrl());
+
+ $this->setFileListAncestorForActor(null, $this->actor);
}
/**
@@ -182,8 +185,8 @@ class FilesSharingAppContext implements Context, ActorAwareInterface {
// Unlike other menus, the Share menu is always present in the DOM, so
// the element could be found when it was no made visible yet due to the
// command not having been processed by the browser.
- if (!$this->waitForElementToBeEventuallyShown(
- self::shareMenu(), $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
+ if (!WaitFor::elementToBeEventuallyShown(
+ $this->actor, self::shareMenu(), $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
PHPUnit_Framework_Assert::fail("The Share menu is not visible yet after $timeout seconds");
}
@@ -202,18 +205,4 @@ class FilesSharingAppContext implements Context, ActorAwareInterface {
PHPUnit_Framework_Assert::assertContains($text, $this->actor->find(self::textPreview(), 10)->getText());
}
- private function waitForElementToBeEventuallyShown($elementLocator, $timeout = 10, $timeoutStep = 1) {
- $actor = $this->actor;
-
- $elementShownCallback = function() use ($actor, $elementLocator) {
- try {
- return $actor->find($elementLocator)->isVisible();
- } catch (NoSuchElementException $exception) {
- return false;
- }
- };
-
- return Utils::waitFor($elementShownCallback, $timeout, $timeoutStep);
- }
-
}
diff --git a/tests/acceptance/features/bootstrap/WaitFor.php b/tests/acceptance/features/bootstrap/WaitFor.php
new file mode 100644
index 00000000000..038de3e42c2
--- /dev/null
+++ b/tests/acceptance/features/bootstrap/WaitFor.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ *
+ * @copyright Copyright (c) 2018, Daniel Calviño Sánchez (danxuliu@gmail.com)
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * Helper class with common "wait for" functions.
+ */
+class WaitFor {
+
+ /**
+ * Waits for the element to be visible.
+ *
+ * @param Actor $actor the Actor used to find the element.
+ * @param Locator $elementLocator the locator for the element.
+ * @param float $timeout the number of seconds (decimals allowed) to wait at
+ * most for the element to be visible.
+ * @param float $timeoutStep the number of seconds (decimals allowed) to
+ * wait before checking the visibility again.
+ * @return boolean true if the element is visible before (or exactly when)
+ * the timeout expires, false otherwise.
+ */
+ public static function elementToBeEventuallyShown(Actor $actor, Locator $elementLocator, $timeout = 10, $timeoutStep = 1) {
+ $elementShownCallback = function() use ($actor, $elementLocator) {
+ try {
+ return $actor->find($elementLocator)->isVisible();
+ } catch (NoSuchElementException $exception) {
+ return false;
+ }
+ };
+
+ return Utils::waitFor($elementShownCallback, $timeout, $timeoutStep);
+ }
+
+ /**
+ * Waits for the element to be hidden (either not visible or not found in
+ * the DOM).
+ *
+ * @param Actor $actor the Actor used to find the element.
+ * @param Locator $elementLocator the locator for the element.
+ * @param float $timeout the number of seconds (decimals allowed) to wait at
+ * most for the element to be hidden.
+ * @param float $timeoutStep the number of seconds (decimals allowed) to
+ * wait before checking the visibility again.
+ * @return boolean true if the element is hidden before (or exactly when)
+ * the timeout expires, false otherwise.
+ */
+ public static function elementToBeEventuallyNotShown(Actor $actor, Locator $elementLocator, $timeout = 10, $timeoutStep = 1) {
+ $elementNotShownCallback = function() use ($actor, $elementLocator) {
+ try {
+ return !$actor->find($elementLocator)->isVisible();
+ } catch (NoSuchElementException $exception) {
+ return true;
+ }
+ };
+
+ return Utils::waitFor($elementNotShownCallback, $timeout, $timeoutStep);
+ }
+
+}
diff --git a/tests/acceptance/features/core/Actor.php b/tests/acceptance/features/core/Actor.php
index bf2f5a7367d..f47373593e9 100644
--- a/tests/acceptance/features/core/Actor.php
+++ b/tests/acceptance/features/core/Actor.php
@@ -61,6 +61,11 @@
class Actor {
/**
+ * @var string
+ */
+ private $name;
+
+ /**
* @var \Behat\Mink\Session
*/
private $session;
@@ -83,12 +88,14 @@ class Actor {
/**
* Creates a new Actor.
*
+ * @param string $name the name of the actor.
* @param \Behat\Mink\Session $session the Mink Session used to control its
* web browser.
* @param string $baseUrl the base URL used when solving relative URLs.
* @param array $sharedNotebook the notebook shared between all actors.
*/
- public function __construct(\Behat\Mink\Session $session, $baseUrl, &$sharedNotebook) {
+ public function __construct($name, \Behat\Mink\Session $session, $baseUrl, &$sharedNotebook) {
+ $this->name = $name;
$this->session = $session;
$this->baseUrl = $baseUrl;
$this->sharedNotebook = &$sharedNotebook;
@@ -96,6 +103,15 @@ class Actor {
}
/**
+ * Returns the name of this Actor.
+ *
+ * @return string the name of this Actor.
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
* Sets the base URL.
*
* @param string $baseUrl the base URL used when solving relative URLs.
diff --git a/tests/acceptance/features/core/ActorContext.php b/tests/acceptance/features/core/ActorContext.php
index d6fb63694ec..2cdc4b01ff1 100644
--- a/tests/acceptance/features/core/ActorContext.php
+++ b/tests/acceptance/features/core/ActorContext.php
@@ -135,7 +135,7 @@ class ActorContext extends RawMinkContext {
$this->actors = array();
$this->sharedNotebook = array();
- $this->actors["default"] = new Actor($this->getSession(), $this->getMinkParameter("base_url"), $this->sharedNotebook);
+ $this->actors["default"] = new Actor("default", $this->getSession(), $this->getMinkParameter("base_url"), $this->sharedNotebook);
$this->actors["default"]->setFindTimeoutMultiplier($this->actorTimeoutMultiplier);
$this->currentActor = $this->actors["default"];
@@ -159,7 +159,7 @@ class ActorContext extends RawMinkContext {
*/
public function iActAs($actorName) {
if (!array_key_exists($actorName, $this->actors)) {
- $this->actors[$actorName] = new Actor($this->getSession($actorName), $this->getMinkParameter("base_url"), $this->sharedNotebook);
+ $this->actors[$actorName] = new Actor($actorName, $this->getSession($actorName), $this->getMinkParameter("base_url"), $this->sharedNotebook);
$this->actors[$actorName]->setFindTimeoutMultiplier($this->actorTimeoutMultiplier);
}