From 572eebbfc4c1709666e45d4eaa272c7efc83a5cf Mon Sep 17 00:00:00 2001 From: Astrid Date: Thu, 12 Jan 2017 21:22:50 +0100 Subject: [PATCH] Update to selenium_v3.0.1.2 (#291) * Update selenium to v3.0.1.2 * Code style * JoomlaBrowser to v3.6.5.1 --- RoboFile.php | 197 +++++++++++++++--- codeception.yml | 15 ++ composer.json | 4 +- .../AdministratorWeblinksCest.php | 96 +++++++-- 4 files changed, 264 insertions(+), 48 deletions(-) diff --git a/RoboFile.php b/RoboFile.php index 810279a..02bfc0a 100644 --- a/RoboFile.php +++ b/RoboFile.php @@ -5,7 +5,11 @@ * Download robo.phar from http://robo.li/robo.phar and type in the root of the repo: $ php robo.phar * Or do: $ composer update, and afterwards you will be able to execute robo like $ php vendor/bin/robo * - * @see http://robo.li/ + * @package Joomla.Site + * @subpackage RoboFile + * + * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt */ require_once 'vendor/autoload.php'; @@ -15,6 +19,13 @@ if (!defined('JPATH_BASE')) define('JPATH_BASE', __DIR__); } +/** + * Modern php task runner for Joomla! Browser Automated Tests execution + * + * @package RoboFile + * + * @since 1.0 + */ class RoboFile extends \Robo\Tasks { // Load tasks from composer, see composer.json @@ -42,6 +53,12 @@ class RoboFile extends \Robo\Tasks */ private $cmsPath = ''; + /** + * @var array | null + * @since version + */ + private $suiteConfig; + /** * Constructor */ @@ -66,9 +83,9 @@ class RoboFile extends \Robo\Tasks { if ($this->isWindows()) { - // check wehter git.exe or git as command should be used, - // as on window both is possible - if(!$this->_exec('git.exe --version')->getMessage()) + // Check wehter git.exe or git as command should be used, + // As on window both is possible + if (!$this->_exec('git.exe --version')->getMessage()) { return ''; } @@ -77,15 +94,17 @@ class RoboFile extends \Robo\Tasks return '.exe'; } } + return ''; } /** * Executes all the Selenium System Tests in a suite on your machine * - * @param array $opts Array of configuration options: + * @param array $opts Array of configuration options: * - 'use-htaccess': renames and enable embedded Joomla .htaccess file * - 'env': set a specific environment to get configuration from + * * @return mixed */ public function runTests($opts = ['use-htaccess' => false, 'env' => 'desktop']) @@ -129,7 +148,7 @@ class RoboFile extends \Robo\Tasks ->stopOnFail(); /* - // Uncomment this lines if you need to debug selenium errors + Uncomment this lines if you need to debug selenium errors $seleniumErrors = file_get_contents('selenium.log'); if ($seleniumErrors) { $this->say('Printing Selenium Log files'); @@ -143,9 +162,8 @@ class RoboFile extends \Robo\Tasks /** * Executes a specific Selenium System Tests in your machine * - * @param string $seleniumPath Optional path to selenium-standalone-server-x.jar - * @param string $pathToTestFile Optional name of the test to be run - * @param string $suite Optional name of the suite containing the tests, Acceptance by default. + * @param string $pathToTestFile Optional name of the test to be run + * @param string $suite Optional name of the suite containing the tests, Acceptance by default. * * @return mixed */ @@ -193,26 +211,28 @@ class RoboFile extends \Robo\Tasks $pathToTestFile = 'tests/' . $suite . '/' . $test; - //loading the class to display the methods in the class + // Loading the class to display the methods in the class require 'tests/' . $suite . '/' . $test; - //logic to fetch the class name from the file name + // Logic to fetch the class name from the file name $fileName = explode("/", $test); $className = explode(".", $fileName[1]); - //if the selected file is cest only than we will give the option to execute individual methods, we don't need this in cept file + // If the selected file is cest only than we will give the option to execute individual methods, we don't need this in cept file $i = 1; + if (strripos($className[0], 'cest')) { $class_methods = get_class_methods($className[0]); $this->say('[' . $i . '] ' . 'All'); $methods[$i] = 'All'; $i++; + foreach ($class_methods as $method_name) { - $reflect = new ReflectionMethod($className[0], $method_name); - if(!$reflect->isConstructor()) + + if (!$reflect->isConstructor()) { if ($reflect->isPublic()) { @@ -222,12 +242,13 @@ class RoboFile extends \Robo\Tasks } } } + $this->say(''); $methodNumber = $this->ask('Please choose the method in the test that you would want to run...'); $method = $methods[$methodNumber]; } - if(isset($method) && $method != 'All') + if (isset($method) && $method != 'All') { $pathToTestFile = $pathToTestFile . ':' . $method; } @@ -243,23 +264,28 @@ class RoboFile extends \Robo\Tasks /** * Run the specified checker tool. Valid options are phpmd, phpcs, phpcpd * - * @param string $tool + * @param string $tool The tool * - * @return bool + * @return bool */ public function runChecker($tool = null) { - if ($tool === null) { + if ($tool === null) + { $this->say('You have to specify a tool name as argument. Valid tools are phpmd, phpcs, phpcpd.'); + return false; } - if (!in_array($tool, array('phpmd', 'phpcs', 'phpcpd') )) { + if (!in_array($tool, array('phpmd', 'phpcs', 'phpcpd'))) + { $this->say('The tool you required is not known. Valid tools are phpmd, phpcs, phpcpd.'); + return false; } - switch ($tool) { + switch ($tool) + { case 'phpmd': return $this->runPhpmd(); @@ -275,12 +301,15 @@ class RoboFile extends \Robo\Tasks * Creates a testing Joomla site for running the tests (use it before run:test) * * @param bool $use_htaccess (1/0) Rename and enable embedded Joomla .htaccess file + * + * @return bool */ public function createTestingSite($use_htaccess = false) { if (!empty($this->configuration->skipClone)) { $this->say('Reusing Joomla CMS site already present at ' . $this->cmsPath); + return; } @@ -348,13 +377,16 @@ class RoboFile extends \Robo\Tasks if (!file_exists($configurationFile)) { $this->say("No local configuration file"); + return null; } $configuration = parse_ini_file($configurationFile); + if ($configuration === false) { $this->say('Local configuration file is empty or wrong (check is it in correct .ini format'); + return null; } @@ -398,6 +430,7 @@ class RoboFile extends \Robo\Tasks if (!file_exists(dirname($this->configuration->cmsPath))) { $this->say("Cms path written in local configuration does not exists or is not readable"); + return 'tests/joomla'; } @@ -411,18 +444,19 @@ class RoboFile extends \Robo\Tasks */ public function runSelenium() { - if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') + if (!$this->isWindows()) { - $this->_exec("vendor/bin/selenium-server-standalone >> selenium.log 2>&1 &"); + $this->_exec("vendor/bin/selenium-server-standalone " . $this->getWebDriver() . ' >> selenium.log 2>&1 &'); } else { - $this->_exec("START java.exe -jar .\\vendor\\joomla-projects\\selenium-server-standalone\\bin\\selenium-server-standalone.jar"); + $this->_exec('START java.exe -jar' . $this->getWebDriver() . + ' vendor\joomla-projects\selenium-server-standalone\bin\selenium-server-standalone.jar '); } - if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') + if ($this->isWindows()) { - sleep(10); + sleep(3); } else { @@ -458,6 +492,8 @@ class RoboFile extends \Robo\Tasks * * @param string $host Web host of the remote server. * @param string $port Server port. + * + * @return void */ public function killSelenium($host = 'localhost', $port = '4444') { @@ -467,6 +503,8 @@ class RoboFile extends \Robo\Tasks /** * Run the phpmd tool + * + * @return void */ private function runPhpmd() { @@ -475,6 +513,8 @@ class RoboFile extends \Robo\Tasks /** * Run the phpcs tool + * + * @return void */ private function runPhpcs() { @@ -483,6 +523,8 @@ class RoboFile extends \Robo\Tasks /** * Run the phpcpd tool + * + * @return void */ private function runPhpcpd() { @@ -508,6 +550,8 @@ class RoboFile extends \Robo\Tasks /** * Executes all unit tests + * + * @return void */ public function runUnit() { @@ -536,6 +580,107 @@ class RoboFile extends \Robo\Tasks $this->_copy('jorobo.dist.ini', 'jorobo.ini'); } - (new \Joomla\Jorobo\Tasks\CopyrightHeader())->run(); + (new \Joomla\Jorobo\Tasks\CopyrightHeader)->run(); + } + + /** + * Detect the correct driver for selenium + * + * @return string the webdriver string to use with selenium + * + * @since version + */ + public function getWebdriver() + { + $suiteConfig = $this->getSuiteConfig(); + $codeceptMainConfig = \Codeception\Configuration::config(); + $browser = $suiteConfig['modules']['config']['JoomlaBrowser']['browser']; + + if ($browser == 'chrome') + { + $driver['type'] = 'webdriver.chrome.driver'; + } + elseif ($browser == 'firefox') + { + $driver['type'] = 'webdriver.gecko.driver'; + } + elseif ($browser == 'MicrosoftEdge') + { + $driver['type'] = 'webdriver.edge.driver'; + + // Check if we are using Windows Insider builds + if ($suiteConfig['modules']['config']['AcceptanceHelper']['MicrosoftEdgeInsiders']) + { + $browser = 'MicrosoftEdgeInsiders'; + } + } + elseif ($browser == 'internet explorer') + { + $driver['type'] = 'webdriver.ie.driver'; + } + + // Check if we have a path for this browser and OS in the codeception settings + if (isset($codeceptMainConfig['webdrivers'][$browser][$this->getOs()])) + { + $driverPath = $codeceptMainConfig['webdrivers'][$browser][$this->getOs()]; + } + else + { + $this->yell( + print_r($codeceptMainConfig) . + 'No driver for your browser. Check your browser in acceptance.suite.yml and the webDrivers in codeception.yml'); + + // We can't do anything without a driver, exit + exit(1); + } + + $driver['path'] = $driverPath; + + return '-D' . implode('=', $driver); + } + + /** + * Get the suite configuration + * + * @param string $suite The suite + * + * @return array + */ + private function getSuiteConfig($suite = 'acceptance') + { + if (!$this->suiteConfig) + { + $this->suiteConfig = Symfony\Component\Yaml\Yaml::parse(file_get_contents("tests/{$suite}.suite.yml")); + } + + return $this->suiteConfig; + } + + /** + * Return the os name + * + * @return string + * + * @since version + */ + private function getOs() + { + $os = php_uname('s'); + + if (strpos(strtolower($os), 'windows') !== false) + { + $os = 'windows'; + } + // Who have thought that Mac is actually Darwin??? + elseif (strpos(strtolower($os), 'darwin') !== false) + { + $os = 'mac'; + } + else + { + $os = 'linux'; + } + + return $os; } } diff --git a/codeception.yml b/codeception.yml index b9a584d..362549c 100644 --- a/codeception.yml +++ b/codeception.yml @@ -8,3 +8,18 @@ settings: bootstrap: _bootstrap.php colors: true memory_limit: 1024M +webdrivers: + firefox: + windows: vendor\joomla-projects\selenium-server-standalone\bin\webdrivers\gecko\geckodriver64.exe + mac: vendor/joomla-projects/selenium-server-standalone/bin/webdrivers/gecko/geckodriver_mac + linux: vendor/joomla-projects/selenium-server-standalone/bin/webdrivers/gecko/geckodriver_linux_64 + chrome: + windows: vendor\joomla-projects\selenium-server-standalone\bin\webdrivers\chrome\chromedriver.exe + mac: vendor/joomla-projects/selenium-server-standalone/bin/webdrivers/chrome/chromedriver_mac + linux: vendor/joomla-projects/selenium-server-standalone/bin/webdrivers/chrome/chromedriver_linux_64 + internet explorer: + windows: vendor\joomla-projects\selenium-server-standalone\bin\webdrivers\internet-explorer32\IEDriverServer.exe + MicrosoftEdge: + windows: vendor\joomla-projects\selenium-server-standalone\bin\webdrivers\edge\MicrosoftWebDriver.exe + MicrosoftEdgeInsiders: + windows: vendor\joomla-projects\selenium-server-standalone\bin\webdrivers\edge-insiders\MicrosoftWebDriver.exe diff --git a/composer.json b/composer.json index a9d277d..cb3c51f 100644 --- a/composer.json +++ b/composer.json @@ -12,10 +12,10 @@ }, "require-dev": { "codeception/codeception": "^2.2", - "joomla-projects/joomla-browser": "v3.6.0.1", + "joomla-projects/joomla-browser": "v3.6.5.1", "composition/robo": "~1", "joomla-projects/robo": "~0", - "joomla-projects/selenium-server-standalone": "v2.53.1", + "joomla-projects/selenium-server-standalone": "v3.0.1.2", "fzaninotto/faker": "^1.6", "joomla-projects/jorobo": "~0.6", "Behat/Gherkin": "^4.4.1" diff --git a/tests/acceptance/administrator/AdministratorWeblinksCest.php b/tests/acceptance/administrator/AdministratorWeblinksCest.php index 138f01d..f9f2175 100644 --- a/tests/acceptance/administrator/AdministratorWeblinksCest.php +++ b/tests/acceptance/administrator/AdministratorWeblinksCest.php @@ -7,8 +7,20 @@ * @license GNU General Public License version 2 or later; see LICENSE.txt */ +/** + * Acceptance cest object class for admin steps + * + * @package Administrator + * + * @since 1.0 + */ class AdministratorWeblinksCest { + /** + * User constructor. + * + * @since version + */ public function __construct() { $this->faker = Faker\Factory::create(); @@ -16,6 +28,15 @@ class AdministratorWeblinksCest $this->url = $this->faker->url(); } + /** + * Method to verify available tabs + * + * @param string $I The weblink object + * + * @since version + * + * @return void + */ public function administratorVerifyAvailableTabs(\Step\Acceptance\weblink $I) { $I->am('Administrator'); @@ -31,6 +52,15 @@ class AdministratorWeblinksCest $I->verifyAvailableTabs(['New Web Link', 'Images', 'Publishing', 'Options', 'Metadata']); } + /** + * Method to create weblink + * + * @param string $I The weblink object + * + * @since version + * + * @return void + */ public function administratorCreateWeblink(\Step\Acceptance\weblink $I) { $I->am('Administrator'); @@ -58,7 +88,15 @@ class AdministratorWeblinksCest } /** + * Method to trash weblink + * + * @param string $I The weblink object + * + * @since version + * * @depends administratorCreateWeblink + * + * @return void */ public function administratorTrashWeblink(AcceptanceTester $I) { @@ -69,24 +107,32 @@ class AdministratorWeblinksCest $I->amGoingTo('Navigate to Weblinks page in /administrator/'); $I->amOnPage('administrator/index.php?option=com_weblinks'); - $I->waitForText('Web Links','30',['css' => 'h1']); + $I->waitForText('Web Links', '30', ['css' => 'h1']); $I->expectTo('see weblinks page'); $I->amGoingTo('Search the just saved weblink'); $I->searchForItem($this->title); - $I->waitForText('Web Links','30',['css' => 'h1']); + $I->waitForText('Web Links', '30', ['css' => 'h1']); $I->amGoingTo('Delete the just saved weblink'); $I->checkAllResults(); $I->clickToolbarButton('Trash'); - $I->waitForText('Web Links','30',['css' => 'h1']); + $I->waitForText('Web Links', '30', ['css' => 'h1']); $I->expectTo('see a success message and the weblink removed from the list'); - $I->see('Web link successfully trashed',['id' => 'system-message-container']); - $I->cantSee($this->title,['id' => 'weblinkList']); + $I->see('Web link successfully trashed', ['id' => 'system-message-container']); + $I->cantSee($this->title, ['id' => 'weblinkList']); } /** - * @depends administratorTrashWeblink + * Method to delete weblink + * + * @param string $I The weblink object + * + * @since version + * + * @depends administratorCreateWeblink + * + * @return void */ public function administratorDeleteWeblink(AcceptanceTester $I) { @@ -97,44 +143,54 @@ class AdministratorWeblinksCest $I->amGoingTo('Navigate to Weblinks page in /administrator/'); $I->amOnPage('administrator/index.php?option=com_weblinks'); - $I->waitForText('Web Links','30',['css' => 'h1']); + $I->waitForText('Web Links', '30', ['css' => 'h1']); $I->expectTo('see weblinks page'); $I->click('Search Tools'); $I->wait(2); $I->selectOptionInChosenById('filter_published', 'Trashed'); $I->amGoingTo('Search the just saved weblink'); $I->searchForItem($this->title); - $I->waitForText('Web Links','30',['css' => 'h1']); + $I->waitForText('Web Links', '30', ['css' => 'h1']); $I->amGoingTo('Delete the just saved weblink'); $I->checkAllResults(); - $I->click(['xpath'=> '//div[@id="toolbar-delete"]/button']); + $I->click(['xpath' => '//div[@id="toolbar-delete"]/button']); $I->acceptPopup(); - $I->waitForText('Web Links','30',['css' => 'h1']); + $I->waitForText('Web Links', '30', ['css' => 'h1']); $I->expectTo('see a success message and the weblink removed from the list'); - $I->see('1 web link successfully deleted.',['id' => 'system-message-container']); - $I->cantSee($this->title,['id' => 'weblinkList']); + $I->see('1 web link successfully deleted.', ['id' => 'system-message-container']); + $I->cantSee($this->title, ['id' => 'weblinkList']); } + /** + * Method to delete weblink + * + * @param string $I The weblink object + * + * @since version + * + * @depends administratorCreateWeblink + * + * @return void + */ public function administratorCreateWeblinkWithoutTitleFails(AcceptanceTester $I) { $I->am('Administrator'); $I->wantToTest('Weblink creation without title fails in /administrator/'); $I->doAdministratorLogin(); - $I->amGoingTo('Navigate to Weblinks page in /administrator/'); $I->amOnPage('administrator/index.php?option=com_weblinks'); - $I->waitForText('Web Links','30',['css' => 'h1']); + $I->waitForText('Web Links', '30', ['css' => 'h1']); $I->expectTo('see weblinks page'); $I->checkForPhpNoticesOrWarnings(); $I->amGoingTo('try to save a weblink with empty title and it should fail'); - $I->click(['xpath'=> "//button[@onclick=\"Joomla.submitbutton('weblink.add')\"]"]); - $I->waitForText('Web Link: New','30',['css' => 'h1']); - $I->click(['xpath'=> "//button[@onclick=\"Joomla.submitbutton('weblink.apply')\"]"]); + $I->click(['xpath' => "//div[@id='toolbar-new']//button"]); + $I->waitForText('Web Link: New', '30', ['css' => 'h1']); + $I->click(['xpath' => "//div[@id='toolbar-apply']//button"]); $I->expectTo('see an error when trying to save a weblink without title and without URL'); - $I->see('Invalid field: Title',['id' => 'system-message-container']); - $I->see('Invalid field: URL',['id' => 'system-message-container']); + $I->see('Invalid field: Title', ['id' => 'system-message-container']); + $I->see('Invalid field: URL', ['id' => 'system-message-container']); } -} \ No newline at end of file +}