diff --git a/composer.json b/composer.json index c077be3d06a6..6472cca43a5f 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "mikey179/vfsStream": "^1.6", "behat/mink-extension": "^2.2", "behat/mink-goutte-driver": "^1.2", - "behat/mink-selenium2-driver": "^1.3", + "behat/mink-selenium2-driver": "dev-master", "sensiolabs/behat-page-object-extension": "^2.0", "behat/behat": "^3.0", "jarnaiz/behat-junit-formatter": "^1.3" diff --git a/composer.lock b/composer.lock index 080fe5fe8d5a..f85dbf466fb2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "e58f3414934ab1ea7f5cd2813eb61e63", + "content-hash": "67e16fd2fefd05ad17877c9456e6b40e", "packages": [ { "name": "bantu/ini-get-wrapper", @@ -3289,16 +3289,16 @@ }, { "name": "behat/mink-selenium2-driver", - "version": "v1.3.1", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/minkphp/MinkSelenium2Driver.git", - "reference": "473a9f3ebe0c134ee1e623ce8a9c852832020288" + "reference": "739b7570f0536bad9b07b511a62c885ee1ec029a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/minkphp/MinkSelenium2Driver/zipball/473a9f3ebe0c134ee1e623ce8a9c852832020288", - "reference": "473a9f3ebe0c134ee1e623ce8a9c852832020288", + "url": "https://api.github.com/repos/minkphp/MinkSelenium2Driver/zipball/739b7570f0536bad9b07b511a62c885ee1ec029a", + "reference": "739b7570f0536bad9b07b511a62c885ee1ec029a", "shasum": "" }, "require": { @@ -3307,7 +3307,7 @@ "php": ">=5.3.1" }, "require-dev": { - "symfony/phpunit-bridge": "~2.7" + "mink/driver-testsuite": "dev-master" }, "type": "mink-driver", "extra": { @@ -3346,7 +3346,7 @@ "testing", "webdriver" ], - "time": "2016-03-05T09:10:18+00:00" + "time": "2017-02-06 08:22:23" }, { "name": "behat/transliterator", @@ -5801,7 +5801,8 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { - "swiftmailer/swiftmailer": 0 + "swiftmailer/swiftmailer": 0, + "behat/mink-selenium2-driver": 20 }, "prefer-stable": false, "prefer-lowest": false, diff --git a/tests/travis/start_behat_tests.sh b/tests/travis/start_behat_tests.sh index 032fe0c26304..574a0bd66428 100644 --- a/tests/travis/start_behat_tests.sh +++ b/tests/travis/start_behat_tests.sh @@ -15,8 +15,16 @@ then else BASE_URL="http://$SRV_HOST_NAME:$SRV_HOST_PORT/$SRV_HOST_URL" fi + +if [ "$BROWSER" == "firefox" ] +then + EXTRA_CAPABILITIES='"seleniumVersion":"2.53.1",' +fi + +EXTRA_CAPABILITIES=$EXTRA_CAPABILITIES'"maxDuration":"3600"' + echo "Running tests on '$BROWSER' ($BROWSER_VERSION) on $PLATFORM" -export BEHAT_PARAMS='{"extensions" : {"Behat\\MinkExtension" : {"browser_name": "'$BROWSER'", "base_url" : "'$BASE_URL'","selenium2":{"capabilities": {"browser": "'$BROWSER'", "version": "'$BROWSER_VERSION'", "platform": "'$PLATFORM'", "name": "'$TRAVIS_REPO_SLUG' - '$TRAVIS_JOB_NUMBER'"}, "wd_host":"http://'$SAUCE_USERNAME:$SAUCE_ACCESS_KEY'@localhost:4445/wd/hub"}}}}' +export BEHAT_PARAMS='{"extensions" : {"Behat\\MinkExtension" : {"browser_name": "'$BROWSER'", "base_url" : "'$BASE_URL'","selenium2":{"capabilities": {"browser": "'$BROWSER'", "version": "'$BROWSER_VERSION'", "platform": "'$PLATFORM'", "name": "'$TRAVIS_REPO_SLUG' - '$TRAVIS_JOB_NUMBER'", "extra_capabilities": {'$EXTRA_CAPABILITIES'}}, "wd_host":"http://'$SAUCE_USERNAME:$SAUCE_ACCESS_KEY'@localhost:4445/wd/hub"}}}}' if [ "$BROWSER" == "internet explorer" ] then diff --git a/tests/ui/features/bootstrap/FeatureContext.php b/tests/ui/features/bootstrap/FeatureContext.php index a23cf5951f41..00d1ab318567 100644 --- a/tests/ui/features/bootstrap/FeatureContext.php +++ b/tests/ui/features/bootstrap/FeatureContext.php @@ -23,6 +23,7 @@ use Behat\Behat\Context\Context; use Behat\Behat\Hook\Scope\BeforeScenarioScope; use Behat\MinkExtension\Context\RawMinkContext; +use Behat\Gherkin\Node\TableNode; use Page\OwncloudPage; use Page\LoginPage; @@ -54,6 +55,28 @@ public function aNotificationShouldBeDisplayedWithTheText($notificationText) ); } + /** + * @Then notifications should be displayed with the text + */ + public function notificationsShouldBeDisplayedWithTheText(TableNode $table) + { + $notifications = $this->owncloudPage->getNotifications(); + $tableRows=$table->getRows(); + PHPUnit_Framework_Assert::assertEquals( + count($tableRows), + count($notifications) + ); + + $notificationCounter=0; + foreach ($tableRows as $row) { + PHPUnit_Framework_Assert::assertEquals( + $row[0], + $notifications[$notificationCounter] + ); + $notificationCounter++; + } + } + /** * @Then I should be redirected to a page with the title :title */ diff --git a/tests/ui/features/bootstrap/FilesContext.php b/tests/ui/features/bootstrap/FilesContext.php index c094198fd966..e109768feb5c 100644 --- a/tests/ui/features/bootstrap/FilesContext.php +++ b/tests/ui/features/bootstrap/FilesContext.php @@ -22,7 +22,7 @@ use Behat\Behat\Context\Context; use Behat\MinkExtension\Context\RawMinkContext; - +use Behat\Gherkin\Node\TableNode; use Page\FilesPage; require_once 'bootstrap.php'; @@ -76,6 +76,47 @@ public function theListOfFilesFoldersDoesNotFitInOneBrowserPage() $this->filesPage->waitTillPageIsloaded(10); } + /** + * @Given I rename the file/folder :fromName to :toName + */ + public function iRenameTheFileFolderTo($fromName, $toName) + { + $this->filesPage->waitTillPageIsloaded(10); + $this->filesPage->renameFile($fromName, $toName, $this->getSession()); + } + + /** + * @When I rename the file/folder :fromName to one of these names + */ + public function iRenameTheFileToOneOfThisNames($fromName, TableNode $table) + { + $this->filesPage->waitTillPageIsloaded(10); + foreach ($table->getRows() as $row) { + $this->filesPage->renameFile($fromName, $row[0], $this->getSession()); + } + + } + + /** + * @Then the file/folder :name should be listed + */ + public function theFileFolderShouldBeListed($name) + { + PHPUnit_Framework_Assert::assertNotNull( + $this->filesPage->findFileRowByName($name, $this->getSession()) + ); + } + + /** + * @Then near the file/folder :name a tooltip with the text :toolTipText should be displayed + */ + public function nearTheFileATooltipWithTheTextShouldBeDisplayed($name, $toolTipText) + { + PHPUnit_Framework_Assert::assertEquals($toolTipText, + $this->filesPage->getTooltipOfFile($name, $this->getSession()) + ); + } + /** * @Then the filesactionmenu should be completely visible after clicking on it */ diff --git a/tests/ui/features/lib/FilesPage.php b/tests/ui/features/lib/FilesPage.php index 76dbdbabf240..7364a8d8c7ff 100644 --- a/tests/ui/features/lib/FilesPage.php +++ b/tests/ui/features/lib/FilesPage.php @@ -25,6 +25,7 @@ use SensioLabs\Behat\PageObjectExtension\PageObject\Page; use SensioLabs\Behat\PageObjectExtension\PageObject\Exception\UnexpectedPageException; +use Behat\Mink\Session; class FilesPage extends OwnCloudPage @@ -39,17 +40,23 @@ class FilesPage extends OwnCloudPage protected $newFileFolderButtonXpath = './/*[@id="controls"]//a[@class="button new"]'; protected $newFolderButtonXpath = './/div[contains(@class, "newFileMenu")]//a[@data-templatename="New folder"]'; protected $newFolderNameInputLabel = 'New folder'; - protected $fileActionMenuXpathByNo = ".//*[@id='fileList']/tr[%d]//a[@data-action='menu']"; + protected $fileActionMenuBtnXpathByNo = ".//*[@id='fileList']/tr[%d]//a[@data-action='menu']"; + protected $fileActionMenuBtnXpath = "//a[@data-action='menu']"; + protected $fileActionMenuXpath = "//div[contains(@class,'fileActionsMenu')]"; + protected $fileNamesXpath = "//span[@class='nametext']"; + protected $fileRowFromNameXpath = "/../../.."; + protected $fileActionXpath = "//a[@data-action='%s']"; + protected $fileRenameInputXpath = "//input[contains(@class,'filename')]"; + protected $fileBusyIndicatorXpath = ".//*[@class='thumbnail' and contains(@style,'loading')]"; + protected $appContentId ="app-content"; + protected $renameActionLabel = "Rename"; + protected $fileTooltipXpath = ".//*[@class='tooltip-inner']"; + //TODO make simpler, only ID .//*[@id='fileList'] protected $fileListXpath = ".//div[@id='app-content-files']//tbody[@id='fileList']"; protected $fileDeleteXpathByNo = ".//*[@id='fileList']/tr[%d]//a[@data-action='Delete']"; private $strForNormalFileName = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; - public function findFileInList($filename) - { - return $this->findLink($filename); - } - /** * created a folder with the given name. * If name is not given a random one is choosen @@ -74,10 +81,134 @@ public function getSizeOfFileFolderList() ); } public function findActionMenuByNo($number) { - $xpath = sprintf($this->fileActionMenuXpathByNo,$number); + $xpath = sprintf($this->fileActionMenuBtnXpathByNo,$number); return $this->find("xpath", $xpath); } + /** + * finds the complete row of the file + * + * @param string $name + * @param Session $session + * @return \Behat\Mink\Element\NodeElement|NULL + */ + public function findFileRowByName($name, Session $session) + { + $lastFileNameCoordinates ["top"] = 0; + $appContentHeight = 0; + $previousFileCounter = 0; + $fileNameSpans = array(); + + $fileNameSpans = $this->find("xpath", $this->fileListXpath)->findAll( + "xpath", $this->fileNamesXpath + ); + //loop to keep on scrolling down to load not viewed files + //when the file count is not increasing, the file is not there + while ($previousFileCounter < count($fileNameSpans)) { + //check every file if the name is the one we are searching for + //but no need to check names that we checked already ($previousFileCounter) + for ($fileCounter = $previousFileCounter; + $fileCounter < count($fileNameSpans); + $fileCounter ++) { + //found the file + if ($fileNameSpans[$fileCounter]->getText() === $name || + strip_tags($fileNameSpans[$fileCounter]->getHtml()) === $name) { + return $fileNameSpans[$fileCounter]->find( + "xpath", $this->fileRowFromNameXpath + ); + } + $previousFileCounter = $fileCounter; + } + + // scroll to the bottom of the page + // we need to scroll because the files app does only load a part of + // the files in one screen + $this->scrollDownAppContent(count($fileNameSpans), $session); + + $fileNameSpans = $this->find("xpath", $this->fileListXpath)->findAll( + "xpath", $this->fileNamesXpath + ); + } + } + + /** + * scrolls down the file list, to load not yet displayed files + * @param int $numberOfFilesOld how many files were listed before the scroll. + * So we can guess how long to wait for the loading of new files to finish + * @param Session $session + * @param int $timeout + */ + public function scrollDownAppContent ($numberOfFilesOld, Session $session, $timeout=5) + { + $session->evaluateScript( + '$("#' . $this->appContentId . '").scrollTop($("#' . $this->appContentId . '")[0].scrollHeight);' + ); + + // there is no loading indicator here, so we are going to wait until we have + // more files than before + for ($counter = 0; $counter <= $timeout; $counter ++) { + $fileNameSpans = $this->find("xpath", $this->fileListXpath)->findAll( + "xpath", $this->fileNamesXpath + ); + if (count($fileNameSpans) > $numberOfFilesOld) { + break; + } + sleep(1); + } + } + + /** + * Takes a row of a file and finds the Action Button in it + * @param \Behat\Mink\Element\NodeElement $fileRow + * @return \Behat\Mink\Element\NodeElement|NULL + */ + public function findFileActionButtonInFileRow (\Behat\Mink\Element\NodeElement $fileRow) + { + return $fileRow->find("xpath", $this->fileActionMenuBtnXpath); + } + + /** + * Takes a row of a file and finds the File Action in it + * the File Action Button must be clicked first + * @param \Behat\Mink\Element\NodeElement $fileRow + * @return \Behat\Mink\Element\NodeElement|NULL + */ + public function findFileActionMenuInFileRow (\Behat\Mink\Element\NodeElement $fileRow) + { + return $fileRow->find("xpath", $this->fileActionMenuXpath); + } + + /** + * finds the actual action link in the action menu + * @param string $action + * @param \Behat\Mink\Element\NodeElement $actionMenu + * @return \Behat\Mink\Element\NodeElement|NULL + */ + public function findButtonInActionMenu ($action, \Behat\Mink\Element\NodeElement $actionMenu) + { + return $actionMenu->find("xpath", + sprintf($this->fileActionXpath, $action) + ); + } + + /** + * renames a file + * @param string $fromFileName + * @param string $toFileName + * @param Session $session + */ + public function renameFile($fromFileName, $toFileName, Session $session) + { + $fileRow=$this->findFileRowByName($fromFileName, $session); + $actionMenuBtn=$this->findFileActionButtonInFileRow($fileRow); + $actionMenuBtn->click(); + $actionMenu=$this->findFileActionMenuInFileRow($fileRow); + $this->findButtonInActionMenu($this->renameActionLabel, $actionMenu)->click(); + $fileRow->find("xpath", $this->fileRenameInputXpath)->setValue($toFileName); + $fileRow->find("xpath", $this->fileRenameInputXpath)->blur(); + $this->waitTillElementIsNull($this->fileBusyIndicatorXpath); + } + public function findDeleteByNo($number) { $xpath = sprintf($this->fileDeleteXpathByNo,$number); return $this->find("xpath", $xpath); @@ -98,6 +229,18 @@ public function waitTillPageIsloaded($timeout) } } + /** + * returns the tooltip that is displayed next to the filename if something is wrong + * @param string $fileName + * @param Session $session + * @return string + */ + public function getTooltipOfFile ($fileName, Session $session) + { + $fileRow=$this->findFileRowByName($fileName, $session); + return $fileRow->find("xpath", $this->fileTooltipXpath)->getText(); + } + /** * same as the original open() function but with a more slack * URL verification as oC adds some extra parameters to the URL e.g. diff --git a/tests/ui/features/lib/OwncloudPage.php b/tests/ui/features/lib/OwncloudPage.php index 3ad992ac5487..01405933dcf0 100644 --- a/tests/ui/features/lib/OwncloudPage.php +++ b/tests/ui/features/lib/OwncloudPage.php @@ -46,10 +46,35 @@ public function waitTillPageIsloaded($timeout) } + /** + * + * @param string $xpath + * @param int $timeout + */ + public function waitTillElementIsNull ($xpath, $timeout=10) + { + for ($counter = 0; $counter <= $timeout; $counter ++) { + $element = $this->find("xpath",$xpath); + if ($element === null) { + break; + } + sleep(1); + } + } + public function getNotificationText() { return $this->findById("notification")->getText(); } + public function getNotifications() { + $notificationsText=array(); + $notifications=$this->findById("notification"); + foreach ($notifications->findAll("xpath", "div") as $notification) { + array_push($notificationsText, $notification->getText()); + } + return $notificationsText; + } + /** * finds the own username displayed in the top right corner * @return string diff --git a/tests/ui/features/lib/UsersPage.php b/tests/ui/features/lib/UsersPage.php index 49fc797bcea9..1e31d207fe83 100644 --- a/tests/ui/features/lib/UsersPage.php +++ b/tests/ui/features/lib/UsersPage.php @@ -58,9 +58,8 @@ public function getQuotaOfUser($username) { $userTr = $this->findUserInTable($username); $selectField = $userTr->find('xpath', $this->quotaSelectXpath); - $selectField = $selectField->find( - 'xpath', "//option[@selected='selected']" + 'xpath', "//option[@value='".$selectField->getValue()."']" ); return $selectField->getText(); diff --git a/tests/ui/features/renameFiles.feature b/tests/ui/features/renameFiles.feature new file mode 100644 index 000000000000..10ff1e69de09 --- /dev/null +++ b/tests/ui/features/renameFiles.feature @@ -0,0 +1,52 @@ +Feature: renameFiles + + Background: + Given a regular user exists + And I am logged in as a regular user + And I am on the files page + + Scenario Outline: Rename a file using special characters + When I rename the file "lorem.txt" to + Then the file should be listed + Examples: + |to_file_name | + |'लोरेम।तयक्स्त $%&' | + |'"quotes1"' | + |"'quotes2'" | + + + Scenario Outline: Rename a file that has special characters in its name + When I rename the file to + Then the file should be listed + Examples: + |from_name |to_name | + |"strängé filename (duplicate #2).txt"|"strängé filename (duplicate #3).txt"| + |"'single'quotes.txt" |"single-quotes.txt" | + + Scenario: Rename a file using special characters and check its existence after page reload + When I rename the file "lorem.txt" to "लोरेम।तयक्स्त $%&" + And the page is reloaded + Then the file "लोरेम।तयक्स्त $%&" should be listed + When I rename the file "लोरेम।तयक्स्त $%&" to '"double"quotes.txt' + And the page is reloaded + Then the file '"double"quotes.txt' should be listed + When I rename the file '"double"quotes.txt' to "no-double-quotes.txt" + And the page is reloaded + Then the file "no-double-quotes.txt" should be listed + + Scenario: Rename a file using forbidden characters + When I rename the file "data.zip" to one of these names + |lorem/txt | + |.htaccess | + |lorem\txt | + |\\.txt | + Then notifications should be displayed with the text + |Could not rename "data.zip"| + |Could not rename "data.zip"| + |Could not rename "data.zip"| + |Could not rename "data.zip"| + And the file "data.zip" should be listed + + Scenario: Rename a file putting a name of a file which already exists + When I rename the file "data.zip" to "lorem.txt" + Then near the file "data.zip" a tooltip with the text 'lorem.txt already exists' should be displayed \ No newline at end of file diff --git a/tests/ui/features/renameFolders.feature b/tests/ui/features/renameFolders.feature new file mode 100644 index 000000000000..3f5a2df0696c --- /dev/null +++ b/tests/ui/features/renameFolders.feature @@ -0,0 +1,53 @@ +Feature: renameFolders + + Background: + Given a regular user exists + And I am logged in as a regular user + And I am on the files page + + Scenario Outline: Rename a folder using special characters + When I rename the folder "simple-folder" to + Then the folder should be listed + Examples: + |to_folder_name| + |'सिमप्ले फोल्देर' | + |'"quotes1"' | + |"'quotes2'" | + + Scenario Outline: Rename a folder that has special characters in its name + When I rename the folder to + Then the folder should be listed + Examples: + |from_name |to_name | + |"strängé नेपाली folder"|"strängé नेपाली folder-2"| + |"'single'quotes" |"single-quotes" | + + Scenario: Rename a folder using special characters and check its existence after page reload + When I rename the folder "simple-folder" to "लोरेम।तयक्स्त $%&" + And the page is reloaded + Then the folder "लोरेम।तयक्स्त $%&" should be listed + When I rename the folder "लोरेम।तयक्स्त $%&" to '"double"quotes' + And the page is reloaded + Then the folder '"double"quotes' should be listed + When I rename the folder '"double"quotes' to "no-double-quotes" + And the page is reloaded + Then the folder "no-double-quotes" should be listed + + Scenario: Rename a folder using forbidden characters + When I rename the folder "simple-folder" to one of these names + |simple/folder | + |.htaccess | + |simple\folder | + |\\simple/folder | + |../simple-folder| + Then notifications should be displayed with the text + |Could not rename "simple-folder"| + |Could not rename "simple-folder"| + |Could not rename "simple-folder"| + |Could not rename "simple-folder"| + |Could not rename "simple-folder"| + And the folder "simple-folder" should be listed + + Scenario: Rename a folder putting a name of a file which already exists + When I rename the folder "simple-folder" to "lorem.txt" + Then near the folder "simple-folder" a tooltip with the text 'lorem.txt already exists' should be displayed \ No newline at end of file diff --git a/tests/ui/skeleton/'single'quotes.txt b/tests/ui/skeleton/'single'quotes.txt new file mode 100644 index 000000000000..b62c3fb2ffd3 --- /dev/null +++ b/tests/ui/skeleton/'single'quotes.txt @@ -0,0 +1,4 @@ +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. +Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \ No newline at end of file diff --git a/tests/ui/skeleton/'single'quotes/for-git-commit b/tests/ui/skeleton/'single'quotes/for-git-commit new file mode 100644 index 000000000000..86459fd55043 --- /dev/null +++ b/tests/ui/skeleton/'single'quotes/for-git-commit @@ -0,0 +1 @@ +this file is only here because git does not allow to commit empty folders \ No newline at end of file