From 034571d2f5324da5d09b6b155411b3d6405ef57c Mon Sep 17 00:00:00 2001 From: Artur Neumann Date: Thu, 19 Oct 2017 16:21:29 +0545 Subject: [PATCH 1/2] allow group named "0" to be deleted --- settings/js/users/groups.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/settings/js/users/groups.js b/settings/js/users/groups.js index 61903d576d7b..7215aa332c07 100644 --- a/settings/js/users/groups.js +++ b/settings/js/users/groups.js @@ -19,6 +19,7 @@ GroupList = { var $li = $userGroupList.find('.isgroup:last-child').clone(); $li .data('gid', gid) + .attr('data-gid', gid) .find('.groupname').text(gid); GroupList.setUserCount($li, usercount); @@ -294,7 +295,7 @@ GroupList = { }, getElementGID: function (element) { - return ($(element).closest('li').data('gid') || '').toString(); + return ($(element).closest('li').attr('data-gid') || '').toString(); }, getEveryoneCount: function () { $.ajax({ From 479aa5b42d8d82587c7bba76ac6a4d7f80bda26d Mon Sep 17 00:00:00 2001 From: Artur Neumann Date: Fri, 20 Oct 2017 13:11:08 +0545 Subject: [PATCH 2/2] UI tests deleting groups --- tests/TestHelpers/SetupHelper.php | 7 ++ .../ui/features/bootstrap/BasicStructure.php | 16 ++- .../ui/features/bootstrap/FeatureContext.php | 32 ++++++ tests/ui/features/bootstrap/UsersContext.php | 57 ++++++++++ tests/ui/features/lib/FilesPageBasic.php | 29 ----- tests/ui/features/lib/OwncloudPage.php | 29 +++++ .../lib/UserPageElement/GroupList.php | 107 ++++++++++++++++++ tests/ui/features/lib/UsersPage.php | 44 ++++++- tests/ui/features/other/users.feature | 43 ++++++- 9 files changed, 332 insertions(+), 32 deletions(-) create mode 100644 tests/ui/features/lib/UserPageElement/GroupList.php diff --git a/tests/TestHelpers/SetupHelper.php b/tests/TestHelpers/SetupHelper.php index 10144b9e752e..81e7e6a39839 100644 --- a/tests/TestHelpers/SetupHelper.php +++ b/tests/TestHelpers/SetupHelper.php @@ -134,6 +134,13 @@ public static function deleteGroup($groupName) { return self::runOcc(['group:delete', $groupName]); } + /** + * + * @return string[] + */ + public static function getGroups() { + return json_decode(self::runOcc(['group:list', '--output=json'])['stdOut']); + } /** * * @param HookScope $scope diff --git a/tests/ui/features/bootstrap/BasicStructure.php b/tests/ui/features/bootstrap/BasicStructure.php index e8032ad1ca17..ce06d1105ce5 100644 --- a/tests/ui/features/bootstrap/BasicStructure.php +++ b/tests/ui/features/bootstrap/BasicStructure.php @@ -360,11 +360,25 @@ public function addUserToCreatedUsersList( * @return void */ public function addGroupToCreatedGroupsList($group) { - if (!in_array($group, $this->createdGroupNames)) { + if (!in_array($group, $this->createdGroupNames, true)) { array_push($this->createdGroupNames, $group); } } + /** + * deletes a group from the lists of groups that were created during test runs + * useful if a group got created during the setup phase but got deleted in a + * test run. We don't want to try to delete this group again in the tear-down phase + * + * @param string $group + * @return void + */ + public function deleteGroupFromCreatedGroupsList($group) { + if (($key = array_search($group, $this->createdGroupNames, true)) !== false) { + unset($this->createdGroupNames[$key]); + } + } + /** * * @param string $username diff --git a/tests/ui/features/bootstrap/FeatureContext.php b/tests/ui/features/bootstrap/FeatureContext.php index e1136f1c445d..fedf4b728a6a 100644 --- a/tests/ui/features/bootstrap/FeatureContext.php +++ b/tests/ui/features/bootstrap/FeatureContext.php @@ -28,6 +28,7 @@ use Page\OwncloudPage; use Page\LoginPage; use TestHelpers\SetupHelper; +use OC\Setup; require_once 'bootstrap.php'; @@ -136,6 +137,37 @@ public function iShouldBeRedirectedToAPageWithTheTitle($title) { PHPUnit_Framework_Assert::assertEquals($title, trim($actualTitle)); } + /** + * @Then the group named :name should not exist + * @return void + */ + public function theGroupNamedShouldNotExist($name) { + if (in_array($name, SetupHelper::getGroups(), true)) { + throw new Exception("group '" . $name . "' exists but should not"); + } + } + + /** + * @Then /^these groups should (not|)\s?exist:$/ + * expects a table of groups with the heading "groupname" + * @param string $shouldOrNot (not|) + * @param TableNode $table + * @return void + */ + public function theseGroupsShouldNotExist($shouldOrNot, TableNode $table) { + $should = ($shouldOrNot !== "not"); + $groups = SetupHelper::getGroups(); + foreach ($table as $row) { + if (in_array($row['groupname'], $groups, true) !== $should) { + throw new Exception( + "group '" . $row['groupname'] . + "' does" . ($should ? " not" : "") . + " exist but should" . ($should ? "" : " not") + ); + } + } + } + /** * @BeforeScenario * @param BeforeScenarioScope $scope diff --git a/tests/ui/features/bootstrap/UsersContext.php b/tests/ui/features/bootstrap/UsersContext.php index 969a6e29a054..3ea042b921cc 100644 --- a/tests/ui/features/bootstrap/UsersContext.php +++ b/tests/ui/features/bootstrap/UsersContext.php @@ -37,6 +37,10 @@ class UsersContext extends RawMinkContext implements Context { private $usersPage; + /** + * + * @var FeatureContext + */ private $featureContext; /** @@ -109,6 +113,59 @@ public function iCreateAUserInTheGUI( } } + /** + * @When I delete the group named :name + * @return void + */ + public function iDeleteTheGroupNamed($name) { + $this->usersPage->deleteGroup($name, $this->getSession()); + $this->featureContext->deleteGroupFromCreatedGroupsList($name); + } + + /** + * @When I delete these groups: + * expects a table of groups with the heading "groupname" + * @param TableNode $table + * @return void + */ + public function iDeleteTheseGroups(TableNode $table) { + foreach ($table as $row) { + $this->iDeleteTheGroupNamed($row['groupname']); + } + } + + /** + * @Then the group named :name should not be listed + * @param string $name + * @return void + */ + public function theGroupNamedShouldNotBeListed($name) { + if (in_array($name, $this->usersPage->getAllGroups(), true)) { + throw new Exception("group '" . $name . "' is listed but should not"); + } + } + + /** + * @Then /^these groups should (not|)\s?be listed:$/ + * expects a table of groups with the heading "groupname" + * @param string $shouldOrNot (not|) + * @param TableNode $table + * @return void + */ + public function theseGroupsShouldBeListed($shouldOrNot, TableNode $table) { + $should = ($shouldOrNot !== "not"); + $groups = $this->usersPage->getAllGroups(); + foreach ($table as $row) { + if (in_array($row['groupname'], $groups, true) !== $should) { + throw new Exception( + "group '" . $row['groupname'] . + "' is" . ($should ? " not" : "") . + " listed but should" . ($should ? "" : " not") . " be" + ); + } + } + } + /** * @When the users page is reloaded * @return void diff --git a/tests/ui/features/lib/FilesPageBasic.php b/tests/ui/features/lib/FilesPageBasic.php index 88193b4f55df..ff309ba183c0 100644 --- a/tests/ui/features/lib/FilesPageBasic.php +++ b/tests/ui/features/lib/FilesPageBasic.php @@ -59,35 +59,6 @@ public function getSizeOfFileFolderList() { ); } - /** - * Surround the text with single or double quotes, whichever does not - * already appear in the text. If the text contains both single and - * double quotes, then throw an InvalidArgumentException. - * - * The returned string is intended for use as part of an xpath (v1). - * xpath (v1) has no way to escape the quote character within a string - * literal. So there is no way to directly use a string containing - * both single and double quotes. - * - * @param string $text - * @return string the text surrounded by single or double quotes - * @throws \InvalidArgumentException - */ - public function quotedText($text) { - if (strstr($text, "'") === false) { - return "'" . $text . "'"; - } else if (strstr($text, '"') === false) { - return '"' . $text . '"'; - } else { - // The text contains both single and double quotes. - // With current xpath v1 there is no way to encode that. - throw new \InvalidArgumentException( - "mixing both single and double quotes is unsupported - '" - . $text . "'" - ); - } - } - /** * @param int $number * @return \Behat\Mink\Element\NodeElement|null diff --git a/tests/ui/features/lib/OwncloudPage.php b/tests/ui/features/lib/OwncloudPage.php index d96db41a9633..94d833a3098f 100644 --- a/tests/ui/features/lib/OwncloudPage.php +++ b/tests/ui/features/lib/OwncloudPage.php @@ -406,4 +406,33 @@ protected function cleanInputAndSetValue(NodeElement $inputField, $value) { throw new \Exception("value of input field is not what we expect"); } } + + /** + * Surround the text with single or double quotes, whichever does not + * already appear in the text. If the text contains both single and + * double quotes, then throw an InvalidArgumentException. + * + * The returned string is intended for use as part of an xpath (v1). + * xpath (v1) has no way to escape the quote character within a string + * literal. So there is no way to directly use a string containing + * both single and double quotes. + * + * @param string $text + * @return string the text surrounded by single or double quotes + * @throws \InvalidArgumentException + */ + public function quotedText($text) { + if (strstr($text, "'") === false) { + return "'" . $text . "'"; + } else if (strstr($text, '"') === false) { + return '"' . $text . '"'; + } else { + // The text contains both single and double quotes. + // With current xpath v1 there is no way to encode that. + throw new \InvalidArgumentException( + "mixing both single and double quotes is unsupported - '" + . $text . "'" + ); + } + } } diff --git a/tests/ui/features/lib/UserPageElement/GroupList.php b/tests/ui/features/lib/UserPageElement/GroupList.php new file mode 100644 index 000000000000..4314c1467510 --- /dev/null +++ b/tests/ui/features/lib/UserPageElement/GroupList.php @@ -0,0 +1,107 @@ + + * @copyright 2017 Artur Neumann artur@jankaritech.com + * + * This code 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 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 + * + */ + +namespace Page\UserPageElement; + +use Behat\Mink\Element\NodeElement; +use Page\OwncloudPage; +use SensioLabs\Behat\PageObjectExtension\PageObject\Exception\ElementNotFoundException; + +/** + * The list of groups + * + */ +class GroupList extends OwncloudPage { + + /** + * @var NodeElement of this element + */ + protected $groupListElement; + protected $allGroupsXpath = "//li[@class='isgroup']"; + protected $groupLiXpath = "//li[@data-gid=%s]"; + protected $deleteBtnXpath = "//a[@class='action delete']"; + + /** + * sets the NodeElement for the current group list + * a little bit like __construct() but as we access this "sub-page-object" + * from an other Page Object by $this->getPage("OwncloudPageElement\\GroupList") + * there is no real __construct() that can take arguments + * + * @param \Behat\Mink\Element\NodeElement $groupListElement + * @return void + */ + public function setElement(NodeElement $groupListElement) { + $this->groupListElement = $groupListElement; + } + + /** + * + * @param string $name + * @throws ElementNotFoundException + * @return \Behat\Mink\Element\NodeElement + */ + public function selectGroup($name) { + $name = $this->quotedText($name); + $groupLi = $this->groupListElement->find( + "xpath", sprintf($this->groupLiXpath, $name) + ); + if ($groupLi === null) { + throw new ElementNotFoundException("cannot find group list element"); + } + $groupLi->click(); + return $groupLi; + } + + /** + * deletes a group in the UI + * + * @param string $name + * @throws ElementNotFoundException + * @return void + */ + public function deleteGroup($name) { + $groupLi = $this->selectGroup($name); + $deleteButton = $groupLi->find("xpath", $this->deleteBtnXpath); + if ($deleteButton === null) { + throw new ElementNotFoundException("cannot find delete button"); + } + $deleteButton->click(); + } + + /** + * returns all group names in an array + * + * @return string[] + */ + public function namesToArray() { + $allGroupElements = $this->groupListElement->findAll( + "xpath", $this->allGroupsXpath + ); + $allGroups = []; + foreach ($allGroupElements as $element) { + $allGroups[] = $element->getText(); + } + return $allGroups; + } +} + \ No newline at end of file diff --git a/tests/ui/features/lib/UsersPage.php b/tests/ui/features/lib/UsersPage.php index 406ed8ae3004..5397c95b11ab 100644 --- a/tests/ui/features/lib/UsersPage.php +++ b/tests/ui/features/lib/UsersPage.php @@ -24,7 +24,6 @@ use Behat\Mink\Element\NodeElement; use Behat\Mink\Session; -use SensioLabs\Behat\PageObjectExtension\PageObject\Page; use SensioLabs\Behat\PageObjectExtension\PageObject\Exception\ElementNotFoundException; /** @@ -61,6 +60,7 @@ class UsersPage extends OwncloudPage { protected $newUserGroupXpath = ".//*[@id='newuser']//ul[@class='multiselectoptions down']//label[@title='%s']/.."; protected $newUserAddGroupBtnXpath = ".//*[@id='newuser']//ul[@class='multiselectoptions down']//li[@title='add group']"; protected $createGroupWithNewUserInputXpath = ".//*[@id='newuser']//ul[@class='multiselectoptions down']//input[@type='text']"; + protected $groupListId = "usergrouplist"; /** * @param string $username * @return NodeElement for the requested user in the table @@ -255,4 +255,46 @@ public function setQuotaOfUserTo($username, $quota, Session $session) { } $this->waitForOutstandingAjaxCalls($session); } + + /** + * + * @throws ElementNotFoundException + * @return \Page\UserPageElement\GroupList + */ + private function getGroupListElement() { + $groupListElement = $this->findById($this->groupListId); + if ($groupListElement === null) { + throw new ElementNotFoundException("cannot find group list element"); + } + + /** + * + * @var \Page\UserPageElement\GroupList $groupList + */ + $groupList = $this->getPage("UserPageElement\\GroupList"); + $groupList->setElement($groupListElement); + return $groupList; + } + + /** + * returns all group names as an array + * + * @return string[] + */ + public function getAllGroups() { + $groupList = $this->getGroupListElement(); + return $groupList->namesToArray(); + } + + /** + * + * @param string $name + * @param Session $session + * @return void + */ + public function deleteGroup($name, Session $session) { + $groupList = $this->getGroupListElement(); + $groupList->deleteGroup($name); + $this->waitForAjaxCallsToStartAndFinish($session); + } } \ No newline at end of file diff --git a/tests/ui/features/other/users.feature b/tests/ui/features/other/users.feature index dd1d51086aaf..ce4fc10222c3 100644 --- a/tests/ui/features/other/users.feature +++ b/tests/ui/features/other/users.feature @@ -42,4 +42,45 @@ Feature: users And I logout And I login with username "guiusr1" and password "pwd" Then I should be redirected to a page with the title "Files - ownCloud" - \ No newline at end of file + + Scenario: delete groups + And these groups exist: + |groupname | + |do-not-delete | + |grp1 | + |0 | + |false | + |quotes' | + |quotes" | + |do-not-delete2| + And I am on the users page + When I delete these groups: + |groupname| + |grp1 | + |0 | + |false | + |quotes' | + |quotes" | + And the users page is reloaded + Then these groups should be listed: + |groupname | + |do-not-delete | + |do-not-delete2| + But these groups should not be listed: + |groupname| + |grp1 | + |0 | + |false | + |quotes' | + |quotes" | + And these groups should exist: + |groupname | + |do-not-delete | + |do-not-delete2| + But these groups should not exist: + |groupname| + |grp1 | + |0 | + |false | + |quotes' | + |quotes" | \ No newline at end of file